1. 程式人生 > 實用技巧 >LeetCode DP篇-揹包問題(416)

LeetCode DP篇-揹包問題(416)

416. 分割等和子集

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

注意:

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

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

輸出: true

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

示例 2:

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

輸出: false

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

solution 1 二維陣列

class Solution {
    public boolean canPartition(int[] nums) {
        int sum = 0;
        for(int i = 0; i < nums.length; i++){
            sum += nums[i];
        }
        //和為奇數,不可能存在
        if (sum%2 != 0) return false;
        sum /= 2;
        //預設為false
        boolean[][] dp = new boolean[nums.length+1][sum+1];
        //base case
        for(int i = 0; i < nums.length+1; i++){
            dp[i][0] = true;
        }
        //狀態轉移方程
        for (int i = 1; i < nums.length+1; i++){
            for (int j = 1; j < sum+1; j++){
                //剩下空間裝不下,不裝入
                if (j-nums[i-1] < 0){
                    dp[i][j] = dp[i-1][j];
                }else{
                    //剩下空間可裝入的情況下,裝入後剩下為0,即為true
                    dp[i][j] = dp[i-1][j] || dp[i-1][j-nums[i-1]];
                }
            }
        }
        return dp[nums.length][sum];
    }
}
//分成兩個和相等的子集,等於找到和為總數和二分之一的陣列,即0-1揹包問題

solution2 一維陣列

class Solution {
    public boolean canPartition(int[] nums) {
        int sum = 0;
        for(int i = 0; i < nums.length; i++){
            sum += nums[i];
        }
        //和為奇數,不可能存在
        if (sum%2 != 0) return false;
        sum /= 2;
        //預設為false 每一次只依靠nums陣列的前一個
        boolean[] dp = new boolean[sum+1];
        //base case
        dp[0] = true;
        
        //狀態轉移方程
        for (int i = 0; i < nums.length; i++){
            for (int j = sum; j >= 0; j--){
                //剩下空間可裝入時
                if (j-nums[i] >= 0){
                    dp[j] = dp[j] || dp[j-nums[i]];
                }
            }
        }
        return dp[sum];
    }
}