Leetcode——分割等和
阿新 • • 發佈:2019-01-01
題目描述:給定一個只包含正整數的非空陣列。是否可以將這個陣列分割成兩個子集,使得兩個子集的元素和相等。
解題思路:
-
可以看成一個揹包大小為 sum/2 的 0-1 揹包問題。
class Solution { public boolean canPartition(int[] nums) { int sum = sum(nums); if(sum%2!=0) return false; int w = sum / 2; boolean dp[] = new boolean[w+1]; dp[0] = true; for(int num:nums){ for(int j = w;j>=num;j--) dp[j] = dp[j]||dp[j-num]; } return dp[w]; } public int sum(int[] nums){ int sum = 0; for(int x:nums) sum += x; return sum; } }
拓展——改變一組數的正負號使得它們的和為一給定數
題目描述:給定一個非負整數陣列,a1, a2, ..., an, 和一個目標數,S。現在你有兩個符號 + 和 -。對於陣列中的任意一個整數,你都可以從 + 或 -中選擇一個符號新增在前面。返回可以使最終陣列和為目標數 S 的所有新增符號的方法數。
解題思路:
- 該問題可以轉換為 Subset Sum 問題,從而使用 0-1 揹包的方法來求解。
- 可以將這組數看成兩部分,P 和 N,其中 P 使用正號,N 使用負號,有以下推導:
因此只要找到一個子集,令它們都取正號,並且和等於 (target + sum(nums))/2,就證明存在解。
class Solution { public int findTargetSumWays(int[] nums, int S) { int sum = sum(nums); if(S>sum||(sum+S)%2!=0) return 0; int w = (sum + S)/2; int[] dp = new int[w+1]; dp[0] = 1; for(int num:nums){ for(int j = w;j>=num;j--) dp[j] = dp[j] + dp[j-num]; } return dp[w]; } public int sum(int[] nums){ int sum = 0; for(int num:nums) sum += num; return sum; } }