專欄 | 九章演算法
網址 | www.jiuzhang.com
題目描述
給一個nums[]陣列,如[1, 2, 4]
將這些陣列合使得: 這些數的和是給出的一個target,如使這些數的和等於4
求這樣的組合有多少個?
樣例
[1, 1, 1, 1]
[1, 1, 2]
[1, 2, 1]
[2, 1, 1]
[2, 2]
[4]
這些組合都可以,他們的和都是4
所以答案是6
演算法分析
1.直觀的想法就是把所有的組合全都找出來,再計算他們的個數就可以了。那麼,怎麼找所有的組合呢?首先你有一個nums陣列,一個target。首先想,能不能把這個問題分解成子問題?可以。以題目描述為例,需要[1,2,4]組合成4,可以分解為3個子問題:
序列的第一個數為1,讓[1,2,4]組合成3
序列的第一個數為2,讓[1,2,4]組合成2
序列的第一個數為4,讓[1,2,4]組合成0
2.上述的想法用DFS就可以實現,設N為nums陣列的長度,M為target,但是複雜度達到了O(N^M),這個複雜度太高了。 換一個角度來想一想,假設dp[i]為讓[1,2,4]為i的組合的數目,如果我dp[1],dp[2],dp[3]都已經求出來了,如何去求dp[4]呢?dp[4]可以由哪些子問題得到呢?這個思路和上面的過程是一樣的。
序列的第一個數為1,加dp[3]得到
序列的第一個數為2,加dp[2]得到
序列的第一個數為4,加dp[0]得到
3.dp[0] = 1
dp[1] = 第一個數為1,然後加dp[0]得到 = dp[0] = 1
dp[2] = 第一個數為1,然後加dp[1] + 第一個數為2,然後加dp[0] = dp[1] + dp[0] = 2
dp[3] = 第一個數為1,然後加dp[2] + 第一個數為2,然後加dp[1] = dp[2] + dp[1] = 3
dp[4] = 第一個數為1,然後加dp[3] + 第一個數為2,然後加dp[2] + 第一個數為3,然後加dp[1] = dp[3] + dp[2] + dp[1] = 6
4.於是dp方程為dp[i] = dp[i-nums[1]] + dp[i-nums[2]] + ... + dp[i-nums[N]],初始化dp[0] = 1。複雜度O(NM)。
可以發現,第一種思路和第二種思路其實很相近,他們的區別就是,第二種思路對所有的子過程只計算了一遍,第一種思路可能對一個子過程計算很多遍,例:設dfs(i)可以求出目標為i的結果,dfs(4) = dfs(3) + dfs(2) + dfs(0) = dfs(2) + dfs(1) + dfs(2) + dfs(0) 展開到這一步的時候就可以發現dfs(2)已經被計算了2遍了,而在第二種思路中,每個子過程只會被計算一遍,那麼,可不可以讓第一種想法計運算元過程的時候只計算一遍呢?可以,那就是記憶化搜尋。
5.因為題目沒說資料是否是遞增,可以考慮給陣列排序,排序過後 一旦遇到 i - nums[j] < 0的,就可以直接退出迴圈。
參考程式碼
面試官角度分析
這道題目的是揹包問題當中比較難的面試題目,如果會做01揹包,能夠擴充想到這道題目多重揹包怎麼樣處理n個揹包數目,那麼這道題目就能夠迎刃而解,能夠想出O(n*target)時間複雜度的演算法那麼久可以達到hire
LintCode相關聯絡題
登陸www.lintcode.com, 搜尋 backpack即可。
Backpack-i
Backpack-ii
Backpack-iii
Backpack-v
推薦閱讀
- 12 個 tips 教你搞定 onsite!
- 25 個 questions, 教你向面試官提問!
- 10 個 tips 教你搞定電面!
- 北美IT企業fulltime薪資大曝光
- IT 簡歷模板大放送 | 《如何寫好技術簡歷》講座精華總結
- 面試遇到做過的題怎麼辦?
- 冷凍期大揭祕 | Google、FB、Amazon、Linkedin冷凍期
- 面試前如何瞭解一家IT企業?試試官方技術部落格!
- Google晉升機制 | 大公司如何升級打怪, 獲得晉升?
歡迎關注我的微信公眾號:九章演算法(ninechapter)。
精英程式設計師交流社群,定期釋出面試題、面試技巧、求職資訊等