LeetCode刷題日記 416. 分割等和子集

Alezzzzzz發表於2020-10-11

題目給出一個陣列nums,陣列中包含一些正整數,問能夠將這個陣列分成兩個子集,使得這兩個子集相等。首先一上來的想法是將數列中所有的數和求出,然後看陣列中能不能將其中的某些陣列成總和的一半。這裡需要用到動態規劃的思想。用dp[i][j]來表示陣列從0到i範圍內能否表示數字j。我們用size函式可以得到陣列n,通過求合再除以2可以得到目標target。然後我們就能建立dp陣列如下:

vector<vector <int>>(n,vector<int>(target + 1, 0)) //target + 1防止陣列越界

首先通過思考,我們可以先得到dp陣列中以下兩點的值:

  1. 只要不選取任何陣列,我們就可以組成0,因此dp[i][0] = true;
  2. 當i = 0 時,只有正整數nums[0]可以被選取。因此dp[0][nums[0] = true;

然後,通過推導,我們可以得到以下狀態轉移方程:

dp[i][j] = dp[i-1][j] | dp[i-1][j-nums[i]] (j >= nums[i])

dp[i][j] = dp[i-1][j] (j < nums[i])

最終我們返回答案dp[n][target]即可。

程式碼如下:

class Solution {
public:
    bool canPartition(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        int n = nums.size();
        if(n < 2) return false;
        int sum = 0;
        for(int i = 0; i < n; ++i)
        {
            sum += nums[i];
        }
        if(sum % 2 != 0) return false;
        int target = sum / 2;

        vector<vector<int>> dp(n, vector<int>(target + 1, 0));
        for (int i = 0; i < n; i++) {
            dp[i][0] = true;
        }
        dp[0][nums[0]] = true;
        for (int i = 1; i < n; i++) {
            int num = nums[i];
            for (int j = 1; j <= target; j++) {
                if (j >= num) {
                    dp[i][j] = dp[i - 1][j] | dp[i - 1][j - num];
                } else {
                    dp[i][j] = dp[i - 1][j];
                }
            }
        }
        return dp[n - 1][target];

    }
};

 

相關文章