前端學習算法3:一道來自頭條的面試題

朋友去面試頭條的前端,二面,第一個題目,就是下面這張紙,面試官也會給一張紙要求手寫答案。若是你看到就馬上知道了怎麼解答,那能夠直接忽略本文了,或者有更好的寫法,直接評論區留言吧,謝謝~前端

個人學習風格老是想着按部就班,下面從幾個小題開始。面試

1 簡單題目熱身(簡單場景遞歸一下)

題目:給定一個整數數組 nums 和一個目標值 target,請你在該數組中找出和爲目標值的那 兩個 整數,並返回他們組成的數組。 你不能重複利用這個數組中一樣的元素。算法

其實就是一個數組,找出兩個元素,他們的和是指定的值,可是不能一直就一個元素,也就是說加數組只有4的話,不能返回結果是[4,4]這樣數組

var nums = [8, 9, 2, 15, 7, 1]
var target = 9
var twoSum = function(nums, target) {
    var result = []
    for(var i=0; i<nums.length;i++){
        for(var j=i+1; j<nums.length;j++){
            if(nums[i]+nums[j] === target){
                result.push([nums[i],nums[j]])
            }
         }
    }
    return result
}
console.log( twoSum(nums, target) )
複製代碼

運行結果以下函數

代碼很簡單,也不用什麼解釋吧。不過要引出來的是下面一種解法,遞歸。學習

var nums = [8, 9, 2, 15, 7, 1]
var target = 9

var twoSum = function(nums, target) {
	var result = []

	var _sum = function(nums, target){
	    if(nums.length === 0){
		return false
	    }
            for(var i = 1; i < nums.length; i++){
       		    if((nums[0] + nums[i]) === target){
	    		    result.push([nums[0] , nums[i]])
	    	    }
       	    }
       	    nums.splice(0,1) // 或者使用 nums.shift(),刪除數組第一個元素
       	    return _sum(nums, target)
	 }
	_sum(nums, target)
	return result
}
console.log( twoSum(nums, target) )
複製代碼

運行結果以下,固然,和上述結果是同樣的spa

小結 代碼稍微多了一點,其實思想是同樣的,不過想更好的解釋遞歸,那麼須要再把題目簡化一下3d

題目:仍是上面的題目,加上一個限定條件:你能夠假設每種輸入只會對應一個答案。也就是說對應這樣的題幹數組[11, 7, 10, 2] 只有 [7,2]這樣一個結果。對於只有一個結果這樣的狀況,遞歸的寫法代碼會簡練的多。code

var twoSum = function(nums, target) {
    // 1
    var result = []
    if(nums.length === 0){
        // 2
        return false
    }
    for(var i = 1; i < nums.length; i++){
        if((nums[0] + nums[i]) === target){
    	    result.push([nums[0], nums[i]])
    	    // 3
    	    return result
    	}
    }
    // 4
    nums.shift()
    // 5
    return twoSum(nums, target)
}
console.log( twoSum(nums, target) )
複製代碼

小結 :註釋1 中,會把result置爲[], 那豈不是每次遞歸調用這個方法時候,開始都是重置?答,由於前提條件已經改了,咱們返回的結果只有一個 註釋4 ,修改遞歸執行函數的參數,畢竟要每次不同嘛要否則怎麼進行下去。cdn

提問,真的清楚每一個 return 的做用嗎?好比 註釋5 那裏的return不寫的話,有什麼區別?這個必定要清楚。

2 題目進階(for循環?遞歸?)

根據上面例子,很容易想到3重循環,確實也是能夠解決的,只是那個斷定條件,有些low 而且假如是尋找長度爲4子數組呢?那要for循環4次?顯然不可取

3 迴歸主題(重點理解遞歸時候的return)

提問 ,若是用遞歸,這個問題怎麼解決?

var candidates = [2, 3, 8, 4, 10, 15]
var target = 9

var combinationSum2 = function(candidates, target) {
	const buffer = [];
	const result = [];

    const backTrace = (index, target) => {
        if(target == 0) {
            return result.push(buffer.slice());
        }

        if(target < 0) {
            return;
        }

        if(index === candidates.length) return;

        buffer.push(candidates[index]);
        backTrace(index + 1, target - candidates[index]);
        buffer.pop();

        backTrace(index + 1, target);
    }
    backTrace(0, target);

    return result.filter(item => item.length === 3)
};

console.log(combinationSum2(candidates, target))
複製代碼

運行結果以下

解析代碼

  • 第一次執行 backTrace
  1. 執行 backTrace(index, target) 方法index爲0 target爲9
  2. backTrace方法中,有三個終止條件,在第一次執行時候,這三個return沒有一個會執行
  3. 此時 buffer 爲 [2]
  • 第二次執行 backTrace
  1. 執行 backTrace(index, target) 方法index爲1 target爲7
  2. 三個return沒有執行
  3. 此時 buffer 爲 [2,3]
  • 第三次執行 backTrace
  1. 執行 backTrace(index, target) 方法index爲2 target爲4
  2. 三個return沒有執行
  3. 此時 buffer 爲 [2,3,8]
  • 第四次執行 backTrace
  1. 執行 backTrace(index, target) 方法index爲3 target爲 -4
  2. 由於 target < 0 因此執行第二個return
  3. 在此次執行過程當中 後面代碼沒有執行,buffer沒變
  • 返回到第三次執行 backTrace 的過程當中
  1. 執行 buffer.pop()後 buffer爲 [2,3]
  2. 執行backTrace(index + 1, target) 看上面第三次執行步驟,index爲2,target爲4
  • 第五次執行 backTrace
  1. 執行 backTrace(index, target) 方法index爲3 target爲 4
  2. 三個return沒執行
  3. 此時buffer爲[2,3,4]
  • 第六次執行 backTrace
  1. 執行 backTrace(index, target) 方法index爲4 target爲 0
  2. 執行第一個return , result爲 [[2,3,4]]
  • 返回到第五次執行 backTrace 的過程當中
  1. 執行 buffer.pop()後 buffer爲 [2,3]
  2. 執行backTrace(index + 1, target) 看上面第五次執行步驟,index爲3,target爲4
  • 第七次執行 backTrace
  1. 執行 backTrace(index, target) 方法index爲4 target爲 4
  2. 三個return沒執行
  3. 此時buffer爲[2,3,10]
  • 第八次執行 backTrace
  1. 執行 backTrace(index, target) 方法index爲5 target爲 -6
  2. ...
  3. ...

看到這裏,相信已經明白了這個代碼所作的事情,其實這就是回溯算法,不斷試錯,錯誤的話,回到上個狀態,換參數繼續試錯下去。

其實,最最開始的題目,答案已經有了。由於咱們上面的代碼,最後返回的result中,含有多個和爲目標值的數組,那麼咱們只須要再遍歷一下這個result的每一項,篩選出長度符合要求的便可。

相關文章
相關標籤/搜索