[Likou] 416. Split equal sum subsets<Dynamic programming, backtracking>

[Likou] 416. Split equal sum subsets

You are given a non-empty array nums containing only positive integers. Please determine whether this array can be divided into two subsets so that the sum of the elements of the two subsets is equal.

Example 1:
Input: nums = [1,5,11,5]
Output: true
Explanation: The array can be split into [1, 5, 5] and [11].

Example 2:
Input: nums = [1,2,3,5]
Output: false
Explanation: The array cannot be split into two elements and equal subsets.

提示:
1 <= nums.length <= 200
1 <= nums[i] <= 100

answer

dynamic programming

01 Backpack problem : There are N items and a backpack that can carry a maximum weight of W. The weight of the i-th item is weight[i], and the obtained value is value[i]. Each item can only be used once. Find out which items should be put into the backpack with the highest total value.

  • The volume of the backpack is sum / 2
  • The weight of the product (the element in the collection) to be placed in the backpack is the value of the element, and the value is also the value of the element.
  • If the backpack is exactly full, it means that a subset with a sum of sum / 2 has been found.
  • Each element in the backpack cannot be placed repeatedly

Retrace five steps:

  • Determine the meaning of the dp array and subscripts
    01 In the backpack, dp[j] means: A backpack with a capacity of j can carry items with a maximum value of dp[j]. The
    value of each element in this question is both weight and value.
    dp[j] means that the total capacity of the backpack (the total weight that can be loaded) is j. After putting the items in, the maximum weight on the back is dp[j].
    If the backpack capacity is target, dp[target] is the weight of the backpack after it is filled. , so dp[target] == targetwhen , the backpack is full.
  • Determine the recursive formula
    01 The recursive formula of the backpack is: dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
    Put a numerical value into the backpack, then the weight of item i is nums[i], and its value is also nums[i].
    So the recursion formula: dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);
  • From the definition of how to initialize dp array
    dp[j], first of all dp[0] must be 0. If the values ​​given in the question are all positive integers, then all non-0 subscripts can be initialized to 0. If the values ​​given in the question have negative numbers , then the non-zero subscript must be initialized to negative infinity.
  • Determine the traversal order.
    If a one-dimensional dp array is used, the for loop for item traversal is placed on the outer layer, the for loop for backpack traversal is placed on the inner layer, and the inner for loop is traversed in reverse order.
  • Take an example to deduce the dp array
    dp[j] == j. This shows that the sum of the subsets in the set can just make up the sum j.
    Insert image description here
class B {
    
    
    public boolean canPartition(int[] nums) {
    
    
        if(nums == null || nums.length == 0) {
    
    
            return false;
        }
        int sum = 0;
        for(int num : nums) {
    
    
            sum += num;
        }
        //总和为奇数,不能平分
        if(sum % 2 != 0) {
    
    
            return false;
        }
        
        int target = sum / 2;
        int[] dp = new int[target + 1];
        
        for(int i = 0; i < nums.length; i++) {
    
    
            for(int j = target; j >= nums[i]; j--) {
    
    
                //物品 i 的重量是 nums[i],其价值也是 nums[i]
                dp[j] = Math.max(dp[j], dp[j - nums[i]] + nums[i]);
            }
            //剪枝一下,每一次完成內层的for-loop,立即检查是否dp[target] == target,优化时间复杂度(26ms -> 20ms)
            if(dp[target] == target)
                return true;
        }
        return dp[target] == target;
    }
}

Traceback (will time out)

To take or not to take

class B {
    
    
    public static void main(String[] args) {
    
    
        B b = new B();
        int[] nums = {
    
    1,5,11,5};//true
//        int[] nums = {1,2,3,5};//false
        System.out.println(b.canPartition(nums));
    }

    // 回溯
    List<List<Integer>> res = new ArrayList<>();
    List<Integer> path = new ArrayList<>();

    public boolean canPartition(int[] nums) {
    
    
        int target = 0;
        for (int i = 0; i < nums.length; i++) {
    
    
            target += nums[i];
        }
        if (target % 2 != 0) {
    
    
            return false;
        }

        target = target / 2;
        //Arrays.sort(nums);
        trace(nums, 0, target, 0);

        if (res.size() > 0) {
    
    
            // System.out.println(res);
            return true;
        } else {
    
    
            return false;
        }
    }

    public void trace(int[] nums, int start, int target, int sum) {
    
    
        if (sum == target) {
    
    
            res.add(new ArrayList<>(path));
            return;
        }
        if (sum > target) {
    
    
            return;
        }
        for (int i = start; i < nums.length; i++) {
    
    
            path.add(nums[i]);
            sum += nums[i];
            trace(nums, i + 1, target, sum);
            sum -= nums[i];
            path.remove(path.size() - 1);
        }
    }
}

Guess you like

Origin blog.csdn.net/qq_44033208/article/details/132645991