文章目錄
- 題目描述
- 思路 && 代碼
- 1. 動態規劃 O(nc) 、O(nc)
- 2. 結合滾動數組 O(nc)、O(c)
- 二刷
打卡第十四天~熬夜也得把題目補上= =
題目描述
- 初看題目,想到的思路是用記憶化DFS來找結果來著。。看了題解才知道是背包問題= =
思路 && 代碼
1. 動態規劃 O(nc) 、O(nc)
- 參考了liweiwei的這篇題解,里面給背包問題講了一些相關知識~
- 時空復雜度: n 是 nums 的長度,c 是 sum 的長度。
- dp[i][j]:從[0, i]下標組成的數集里選取元素相加,能否構成 j 。
- 狀態轉移方程:【[0, i - 1] 可以構成 j】| 【[0, i - 1] 可以構成 j - nums[i]】,滿足任一種情況,都可以保證 dp[i][j] == true,因此這里采用 |=
class Solution {public boolean canPartition(int[] nums
) {int sum
= 0;for(int num
: nums
) {sum
+= num
;}if(sum
% 2 == 1) {return false;}int target
= sum
/ 2;boolean[][] dp
= new boolean[nums
.length
][target
+ 1];if(nums
[0] <= target
) {dp
[0][nums
[0]] = true;}for(int i
= 1; i
< nums
.length
; i
++) {for(int j
= 0; j
<= target
; j
++) {dp
[i
][j
] = dp
[i
- 1][j
];if(nums
[i
] <= j
) {dp
[i
][j
] |= dp
[i
- 1][j
- nums
[i
]];}}}return dp
[nums
.length
- 1][target
];}
}
2. 結合滾動數組 O(nc)、O?
- 在1的基礎上,通過滾動數組來減少空間復雜度。在劍指Offer 47 禮物的最大值里,也有用到這個方法~。
- 加入 if(dp[target]) 的判斷實現剪枝效果,可以打敗98%+,這里為了看起來簡潔就不加上了
- 注意:逆序是為了達到無后效性的效果。如果正序,會導致后面的列用到的不是上一行的結果,而是當前行的結果,會導致出錯(可以畫圖理解一下,或者看上面1提到的題解的解釋)
class Solution {public boolean canPartition(int[] nums
) {int sum
= 0;for(int num
: nums
) {sum
+= num
;}if(sum
% 2 == 1) {return false;}int target
= sum
/ 2;boolean[] dp
= new boolean[target
+ 1];if(nums
[0] <= target
) {dp
[nums
[0]] = true;}for(int i
= 1; i
< nums
.length
; i
++) {for(int j
= target
; j
>= 0; j
--) {if(nums
[i
] <= j
) {dp
[j
] |= dp
[j
- nums
[i
]];}}}return dp
[target
];}
}
二刷
背包!
你就說你選不選吧(指元素)
你要能 true 我肯定選啊
class Solution {public boolean canPartition(int[] nums
) {int sum
= 0;for(int num
: nums
) {sum
+= num
;}if((sum
& 1) == 1) {return false;}int target
= sum
/ 2;boolean[][] dp
= new boolean[nums
.length
][target
+ 1];if(nums
[0] <= target
) {dp
[0][nums
[0]] = true;}for(int i
= 1; i
< nums
.length
; i
++) {for(int j
= 0; j
<= target
; j
++) {dp
[i
][j
] = (dp
[i
- 1][j
]) | (nums
[i
] <= j
? dp
[i
- 1][j
- nums
[i
]] : false);}}return dp
[nums
.length
- 1][target
];}
}
class Solution {public boolean canPartition(int[] nums
) {int sum
= 0;for(int num
: nums
) {sum
+= num
;}if((sum
& 1) == 1) {return false;}int target
= sum
/ 2;boolean[] dp
= new boolean[target
+ 1];if(nums
[0] <= target
) {dp
[nums
[0]] = true;}for(int i
= 1; i
< nums
.length
; i
++) {for(int j
= target
; j
>= 0; j
--) {dp
[j
] |= (nums
[i
] <= j
? dp
[j
- nums
[i
]] : false);}}return dp
[target
];}
}
總結
以上是生活随笔為你收集整理的【LeetCode笔记】416. 分割等和子集(Java、动态规划、背包问题、滚动数组)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。