LeetCode416. 分割等和子集
阿新 • • 發佈:2021-01-03
☆☆☆☆☆思路:轉化為揹包問題。 即,是否可以從輸入陣列中挑出一些正整數,使得這些數的和 等於 整個陣列和的一半。
本題與傳統0-1揹包問題的不同在於,傳統0-1 揹包問題要求 選取的物品的重量之和不能超過揹包的容量;而本題選取的數字之和需要 恰好等於 規定的和的一半。
這一點的區別,決定了初始化時,所有值應為False。因此,本題狀態轉移方程為 F(i, c) = F(i - 1, c) || F(i - 1, c - w(i) ), 其中F(n , c)表示 考慮將n個物品填滿容量為C的揹包。時間複雜度為 O(n * sum/2) =O(n * sum)
Step1.狀態定義:dp[i][j] 表示從陣列的[0,i]下標範圍內,選取若干正整數,是否存在一種選取方案使得被選取的正整數的和等於j, 初始時均為false。
Step2.考慮邊界情況:
1. 如果不選取任何正整數,則被選取的正整數為0.因此,dp[i][0] = true
2.當i==0時,只有一個正整數nums[0]可以選取,因此,dp[0][nums(0)] = true。
Step3.狀態轉移:
class Solution { public boolean canPartition(int[] nums) { int n = nums.length; if (n < 2) return false; int sum = 0; for (intnum : nums) { sum += num; } // 如果和是奇數,則不能被平分 if ((sum & 1) == 1) { return false; } /* int target = sum / 2; // dp[i][j] 表示從陣列的[0,i]下標範圍內,選取若干正整數, // 是否存在一種選取方案使得被選取的正整數的和等於j boolean[][] dp = new boolean[n][target + 1]; // 揹包容量 0 ~ target for (int i = 0; i < n; i++) { dp[i][0] = true; // 不選取任何正整數,則被選取的正整數和為0 } if (nums[0] <= target) { dp[0][nums[0]] = true; } for (int i = 1; i < n; i++) { for (int j = 1; j <= target; j++) { dp[i][j] = dp[i-1][j]; if (j >= nums[i]) { dp[i][j] |= dp[i-1][j-nums[i]]; } } } return dp[n-1][target];*/ /** * 空間優化 */ int target = sum / 2; boolean[] dp = new boolean[target + 1]; dp[0] = true; // 只考慮第一個num,看是否能填滿對應的揹包。 if (nums[0] <= target) { dp[nums[0]] = true; } // for (int i = 0; i <= target; i++) { // dp[i] = (nums[0] == i); // } for (int i = 1; i < n; i++) { for (int j = target; j >= nums[i]; j--) { // 注意要倒序計算 dp[j] = dp[j] || (dp[j-nums[i]]); } } return dp[target]; } }