1. 程式人生 > 實用技巧 >416.分割等和子集

416.分割等和子集

給定一個只包含正整數的非空陣列。是否可以將這個陣列分割成兩個子集,使得兩個子集的元素和相等。

注意:

每個陣列中的元素不會超過 100
陣列的大小不會超過 200
示例 1:

輸入: [1, 5, 11, 5]

輸出: true

解釋: 陣列可以分割成 [1, 5, 5] 和 [11].

示例2:

輸入: [1, 2, 3, 5]

輸出: false

解釋: 陣列不能分割成兩個元素和相等的子集.

思路:

  • 動態規劃(0-1 揹包問題);
  • 對於每一個硬幣,可以選擇放入或者不放入揹包;
  • 詳見:LeetCode詳解連結

二維陣列空間:

class Solution {
    public
boolean canPartition(int[] nums) { int n = nums.length, sum = 0; for(int a : nums) sum += a; if(sum % 2 == 1) return false; //奇數直接返回fasle int weight = sum / 2; boolean[][] dp = new boolean[n+1][weight + 1]; for(int i = 0; i <= n; i++) dp[i][0] = true; //第一列置為 true
for(int i = 1; i <= n; i++){ for(int j = 1; j <= weight; j++){ if(j >= nums[i-1]) dp[i][j] = dp[i-1][j] || dp[i-1][j-nums[i-1]]; //對於當前的硬幣,選擇加入或者不加入 else dp[i][j] = dp[i-1][j]; } if(dp[i][weight]) return
true; //滿足條件,提前結束 } return dp[n][weight]; } }

一維壓縮空間:

class Solution {
    public boolean canPartition(int[] nums) {
        int n = nums.length, sum = 0;
        for(int a : nums) sum += a;
        if(sum % 2 == 1) return false; //奇數直接返回fasle
        int weight = sum / 2;
        boolean[] dp = new boolean[weight + 1];
        dp[0] = true; //初始置為 true
        for(int i = 1; i <= n; i++){
            for(int j = weight; j > 0; j--){ //從後往前遍歷,防止 nums[i] = 1 時,從前往後都為 true
                if(j >= nums[i-1]) dp[j] = dp[j] || dp[j-nums[i-1]];
            }
            if(dp[weight]) return true; //滿足條件,提前結束
        }
        return dp[weight];
    }
}