Leetcode 416. Partition Equal Subset Sum
本题的题干很简洁:判断数组是否能分为和相同的两个部分。
思路:受限判断是否有可分的可能,如果整个数组的和为奇数,则一定不可能。然后将问题转化为判断是否能用数组中n-1个数得到sum/2。
方法一 动态规划
数组长为n,和为sum/2,使用n行sum/2+1的数组dp,dp[i][j]表示使用数组0到i的元素,可以得到结果 j 。
数组的的更新顺序与行列顺序一致。即对每一个数组元素,判断1到j是否能被组合得到。
更新方程:
若 j>nums[i] ,则 dp[i][j] = dp[i-1][j] || dp[i-1][j-nums[i]]。
否则, dp[i][j] = dp[i-1][j]。
class Solution { public: bool canPartition(vector<int>& nums) { int sum=0; int maxNum=-1; for(int i=0;i<nums.size();i++){ sum+=nums[i]; maxNum=max(maxNum, nums[i]); } // 若和为奇数或者最大元素大于和的一般,返回false if(sum%2==1 || maxNum>sum/2) return false; // dp[i][j]的含义:nums从0到i的元素可以组合得到j vector<vector<bool>> dp(nums.size(), vector<bool>(sum/2 +1, false)); // 判断目标数(j)为0,或者只取第一个数(nums[0])的情况 for(int i=0;i<nums.size();i++){ dp[i][0]=true; } if(nums[0]<=sum/2) dp[0][nums[0]]=true; for(int i=1;i<nums.size();i++){ for(int j=1;j<=sum/2;j++){ if(j>nums[i]) dp[i][j] = dp[i-1][j] || dp[i-1][j-nums[i]]; else dp[i][j] = dp[i-1][j]; } } return dp[nums.size()-1][sum/2]; } };
方法二 动态规划+循环数组
class Solution { public: bool canPartition(vector<int>& nums) { int sum = 0; for(int& n:nums) sum+=n; if(sum%2==1) return false; sum/=2; // dp[i]的含义:到目前为止i可以被组合出来 vector<int> dp(sum+1, false); dp[0]=true; for(int& n:nums){ // i的遍历顺序反向,确保当前元素(n)不被使用两次 for(int i=sum;i>=n;i--) dp[i] = dp[i] || dp[i-n]; } return dp[sum]; } };
浙公网安备 33010602011771号