vivo 自研“V1”晶片曝光,有望搭載於 X70 Pro 旗艦新機
416.分割等和子集
題目
給你一個 只包含正整數 的 非空 陣列nums 。請你判斷是否可以將這個陣列分割成兩個子集,使得兩個子集的元素和相等。
示例 1:
輸入:nums = [1,5,11,5]
輸出:true
解釋:陣列可以分割成 [1, 5, 5] 和 [11] 。
示例 2:
輸入:nums = [1,2,3,5]
輸出:false
解釋:陣列不能分割成兩個元素和相等的子集。
提示:
1 <= nums.length <= 200
1 <= nums[i] <= 100
來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/partition-equal-subset-sum
著作權歸領釦網路所有。商業轉載請聯絡官方授權,非商業轉載請註明出處。
題解
本題求解是否有和為sum/2的子集。
1.確定dp陣列以及下標的含義
i 表示物品
dp[j] 容量為j的揹包,最大可湊成的子集總數為dp[j]
2.確定遞推公式
i 是遍歷物品,也就是元素 i從0開始代表第0個元素,i從0取到nums.length-1
dp[j] = Math.max(dp[j],dp[j-nums[i]]+nums[i])
3.dp陣列如何初始化
當j=0時,揹包容量為0時
這道題的價值都是正數,所以初始化為0就可以了。
如果為價值有負數,那麼非0下標就需要初始化為負無窮。
4.確定遍歷順序
先遍歷物品從左到右
再遍歷揹包,因為每個物品只放一次為了防止重複使用物品,則從右到左遍歷
for(int i=0;i<len;i++){
//遍歷物品
for(int j=bagWeight;j>=nums[i];j--){
dp[j] = Math.max(dp[j],dp[j-nums[i]]+nums[i])
}
}
5.舉例推導dp陣列
nums= [2,1,3]
bagWeight = 3
dp=[0,2,2,3]
程式碼
class Solution { public boolean canPartition(int[] nums) { int len = nums.length; if (len == 1) return false; int bagWeight = 0; for(int i =0;i<len;i++){ bagWeight+=nums[i]; } if(bagWeight%2==1) return false; //如果和為奇數,因為數組裡只有整數,那麼和的一般肯定右小數,是不可能有的 bagWeight = bagWeight/2; int [] dp = new int [bagWeight+1]; for(int i=0;i<len;i++){ for(int j=bagWeight;j>=nums[i];j--){ dp[j] = Math.max(dp[j],dp[j-nums[i]]+nums[i]); if(dp[j] == bagWeight) return true; //找到了就直接返回 } } return false; } }
這道問題是我學習「揹包」問題的入門問題,所以知道這道題用01揹包解之後,可以解出來。但是看見這道題第一反應是回溯,並沒有看出來用01揹包解。
這個是我在題解學習的
揹包問題的理解
我們拿到題目如何透過題目的不同包裝形式看到裡面揹包問題的不變核心呢?
給定一個揹包容量target,再給定一個數組nums(物品),能否按一定方式選取nums中的元素得到target
注意:
1、揹包容量target和物品nums的型別可能是數,也可能是字串
2、target可能題目已經給出(顯式),也可能是需要我們從題目的資訊中挖掘出來(非顯式)(常見的非顯式target比如sum/2等)
3、選取方式有常見的一下幾種:每個元素選一次/每個元素選多次/選元素進行排列組合
那麼對應的揹包問題就是下面我們要講的揹包分類
1、0/1揹包問題:每個元素最多選取一次
2、完全揹包問題:每個元素可以重複選擇
3、組合揹包問題:揹包中的物品要考慮順序
4、分組揹包問題:不止一個揹包,需要遍歷每個揹包
作者:eh-xing-qing
連結:https://leetcode-cn.com/problems/partition-equal-subset-sum/solution/yi-pian-wen-zhang-chi-tou-bei-bao-wen-ti-a7dd/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。