字節KSUM一道你不知道的算法題


一.前言


文章主要給大家分享一個字節跳動自己出的算法題目–KSUM。作者學習了很多,但是沒有能夠很好的解決這個問題,只會用暴力回溯法解決。如果你有更好的辦法,歡迎評論區發佈出來讓更多人看到,謝謝啦!


二. 有請主角–KSUM


題目

  • 請用算法實現,從給定的無序、不重複的數組data中,取出K個數,找出K數之和和與輸入的SUM相等的所有情況,並使算法的時間/空間複雜度儘量的低。
var ksum = function(data, k , sum){
}
  • 思路
    對於這個題目作者可以想到的就是回溯法一步一步的嘗試結果可不可以,流程如下:
  1. 給定一個無重複數組[1,2,3,4,5,7],我們輸入k爲3,需要返回所有sum爲10的情況。
  2. 用回溯法,也就是暴力法,我來走一遍,首先選擇第一個數,數組[1,2,3,4,5,7]中每一個數都可以被選到,如下圖:


3. 第二步,我們可以以第一個數選擇1爲例,第二個數就可能選擇[2,3,4,5,7]中的任何一個數,如下圖:

  1. 第三步:選擇第三個數,這裏我們以已經選擇1和2爲例第三個數就只能選擇[3,4,5,7],在選擇第三數的時候,我們可以知道選擇7是我們想要的結果,返回到結果的數組中,並退回上一步去找其他情況。如果第三步中都沒有滿足的數,也退回第二步去進行選擇查找的可能的情況,當第二步都沒有符合的情況,就再退回第一步進行查找直到所有的情況都遍歷完,然後返回結果。

三.書寫代碼

我們以寫js爲例

上回溯模板

來自國外某大佬,凡是涉及回溯的都可以使用這個模板

/**
 * backtrack(){
 * if(){
 * //終止條件
 * }
 * 枚舉出每一步可選的列表
 *  for(){
 *   //做出選擇
 *     backtrack()
 *   // 撤銷選擇 回到上一步
 * }
 *
 * }
 */

開始解題

  1. 初始化變量
var ksum = function(data, k , sum){
    let list = [];
    backtrack(data,list,k,sum)
    return list;
}

function backtrack(data, list, k, sum, tempList = [], start = 0){
}
  1. 對數組進行遍歷,選擇
function backtrack(data, list, k, sum, tempList = [], start = 0){
    //tempList 已經做過的選擇
    //for 枚舉出每一步可選的列表
    for(let i = start; i<data.length;i++){
        //數組裏面每一項都要選擇
        tempList.push(data[i]);
        //之後的步驟
        backtrack(data, list, k, sum, tempList.slice(0), i+1)
        //tempList.slice(0)淺複製保存一下之前的結果,以防pop掉,之後返回空數組
        // 撤銷上一步選擇
        tempList.pop();
    }
}

首先做出選擇,且每一項都會被選擇,tempList暫存已經做的選擇,start初始選擇,且對起始位置進行限制(上一步走到哪裏了),i+1下一步的start

  1. 終止條件
if(tempList.length === k ){
        if(tempList.reduce((a,b) => a+b,0) === sum){
            //找到
            list.push(tempList);
        }
        return;//回到上一步
    }

終止條件有兩個,一是選擇的數已經夠了等於k,二是加起來的和等於sum,如果滿足我們將暫存的數組,push到list結果裏面,而且不管滿不滿足都回到上一步。

  1. 書寫完畢,測試
    所有代碼如下:
var ksum = function (data, k, sum) {
    let list = [];
    backtrack(data, list, k, sum)
    return list;
}

function backtrack(data, list, k, sum, tempList = [], start = 0) {
    if (tempList.length === n) {
        if (tempList.reduce((a, b) => a + b, 0) === sum) {
            list.push(tempList);
        }
        return;
    }
    for (let i = start; i < data.length; i++) {
        tempList.push(data[i]);
        backtrack(data, list, k, sum, tempList.slice(0), i + 1)
        tempList.pop();
    }
}

console.log(ksum([1, 2, 3, 4, 5, 6, 7, 8], 3, 10))

結果:

結果正確,書寫結束,模板真好用!!!


結束

文章看到現在也結束啦,如果有錯誤的話就麻煩大家給我指出來吧!如果覺得不錯的話別忘了點個贊👍再走噢!歡迎把你想到的方法寫在評論區喔,作者想要進步,哈哈。

個人博客地址

期待

  • 作者大三正在尋找春招實習中,期待大佬的青睞~
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章