算法-Partition Equal Subset Sum(动态规划)

一直以来,动态规划是我的问题,今天看到了一道动态规划的题,做了好久,也思考了好久,借鉴别人的代码才把这个问题理解到。

题意:

Given a non-empty array containing only positive integers, find if
the array can be partitioned into two subsets such that the sum
of elements in both subsets is equal.

样例:

Given nums = [1, 5, 11, 5], return true
two subsets: [1, 5, 5], [11]

Given nums = [1, 2, 3, 9], return false

基本的意思就是说,给定一个数组,能不能将这个数组分为两个部分,同时这两个部分的和是相同的。

我刚刚看到这个题时,想到的是用回溯法来做,因为这个是回溯法的子集树。但是,超时了!

1.回溯法(超时)

 1     private  boolean flag = false;
 2     public  boolean canPartition(int[] nums) {
 3         Integer target = Arrays.stream(nums).boxed().reduce(0, (a, b) -> a + b);
 4         if(target % 2 != 0){
 5             return false;
 6         }
 7         return backTrack(nums, 0, 0, target / 2);
 8     }
 9
10     private static boolean backTrack(int nums[], int start, int sum , int target) {
11         if(sum == target){
12             flag  = true;
13         }
14         else
15         {
16             for(int i = start; i < nums.length; i++){
17                 if(sum + nums[i] <= target){
18                     backTrack(nums, i + 1, sum + nums[i], target);
19                 }
20             }
21         }
22         return flag;
23     }

后来一想,这个跟0-1背包很像,0-1背包也是选择一些物品来转,而这里是选择一些数字,保证两个部分的和是相同的。于是照着0-1背包的方法来做。

2.类似于0-1背包的做法

 1      public static boolean canPartition(int[] nums) {
 2          int sum = Arrays.stream(nums).reduce(0, Integer::sum);
 3          if (sum % 2 == 1)
 4              return false;
 5          else {
 6              sum /= 2;
 7              int n = nums.length;
 8              // dp[i][j] 表示 如果我们取前i个数字,且背包容量为j的情况下,最多能放入多少东西
 9              int dp[][] = new int[n][sum + 1];
10              // dp[0][0] 为初始状态,表示,没有任何没有东西没有体积,其余部分初始化
11              for (int i = nums[0]; i <= sum; i++) {
12                  dp[0][i] = nums[0];
13              }
14              // 遍历n个数字,即视为n个产品
15              for (int i = 1; i < n; i++) {
16                  // 加入了这种物品后更新状态
17                  for (int j = nums[i]; j <= sum; j++) {
18                      dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - nums[i]] + nums[i]);
19                  }
20              }
21              // 放满了才能表示正好1/2
22              if (dp[n - 1][sum] == sum)
23                  return true;
24              else
25                  return false;
26          }
27      }

后来看了网上其他的代码,感觉另一种方法更好。

3.其他做法(动态规划)

 1     public  boolean canPartition(int[] nums) {
 2          int sum = Arrays.stream(nums).reduce(0, Integer::sum);
 3          int target = sum / 2;
 4          if(sum % 2 != 0){
 5              return false;
 6          }
 7          boolean [] dp = new boolean[target + 1];
 8          dp[0] = true;
 9          for(int i = 0; i < nums.length; i++){
10                 for (int j = target; j >= nums[i]; j--) {
11                     dp[j] = dp[j] || dp[j - nums[i]];
12                 }
13          }
14          return dp[target];
15     }

上面的代码用的是也是动态规划,但是只用了一维数组。

其中意思是:

我们定义dp数组来表示某一个数字是否是数组nums的任意一个集合的和,比如,dp[2]表示的是2是否是nums的任意一个集合的和,如果是的话,那为true,否则为false。所以我们最终看dp[sum / 2](sum为数组nums的和)是否为true。但是我们怎么得到这个dp数组呢?

首先,我们得到dp[sum / 2]就行,所以数组的长度最好是sum + 1,因为dp[0]不在题的范围内,所以dp求出1 ~ sum/2直接的所有值,于是我们可以得到一个二维表(实际上是一维表,但是这里为了演示清楚,才选择二维表)。dp数组默认全部为false,然后后面更新这个数组。如图所示

我们来看一个表:

时间: 2024-12-20 08:39:58

算法-Partition Equal Subset Sum(动态规划)的相关文章

Leetcode 416. Partition Equal Subset Sum

416. Partition Equal Subset Sum Given a non-empty array containing only positive integers, find if the array can be partitioned into two subsets such that the sum of elements in both subsets is equal. Note: Each of the array element will not exceed 1

LN : leetcode 416 Partition Equal Subset Sum

lc 416 Partition Equal Subset Sum 416 Partition Equal Subset Sum Given a non-empty array containing only positive integers, find if the array can be partitioned into two subsets such that the sum of elements in both subsets is equal. Note: Each of th

[动态规划] leetcode 416 Partition Equal Subset Sum

problem:https://leetcode.com/problems/partition-equal-subset-sum/ 经典背包问题.找到是否存在恰好装满sum / 2的物体,可以优化为1D的. class Solution { public: bool canPartition(vector<int>& nums) { int n = nums.size(); int sum = accumulate(nums.begin(), nums.end(), 0); if (s

416. Partition Equal Subset Sum

Problem statement: Given a non-empty array containing only positive integers, find if the array can be partitioned into two subsets such that the sum of elements in both subsets is equal. Note: Each of the array element will not exceed 100. The array

[LeetCode] Partition Equal Subset Sum 相同子集和分割

Given a non-empty array containing only positive integers, find if the array can be partitioned into two subsets such that the sum of elements in both subsets is equal. Note: Both the array size and each of the array element will not exceed 100. Exam

LeetCode Partition Equal Subset Sum

原题链接在这里:https://leetcode.com/problems/partition-equal-subset-sum/description/ 题目: Given a non-empty array containing only positive integers, find if the array can be partitioned into two subsets such that the sum of elements in both subsets is equal.

Partition Equal Subset Sum

Given a non-empty array containing only positive integers, find if the array can be partitioned into two subsets such that the sum of elements in both subsets is equal. Note: Each of the array element will not exceed 100. The array size will not exce

LC 416. Partition Equal Subset Sum

题目 Given a non-empty array containing only positive integers, find if the array can be partitioned into two subsets such that the sum of elements in both subsets is equal. Note: Each of the array element will not exceed 100. The array size will not e

[LeetCode] 416. Partition Equal Subset Sum_Medium tag: backpack

Given a non-empty array containing only positive integers, find if the array can be partitioned into two subsets such that the sum of elements in both subsets is equal. Note: Each of the array element will not exceed 100. The array size will not exce