【 Backpack problem series 】 two, abstract backpack problem

Abstract knapsack problem

[B].

Given a non-empty array containing only positive integers. Is it possible to split this array into two subsets so that the sum of the elements in the two subsets is equal? Note: No more than 100 elements in each array Size no more than 200 Example 1: Input: [1, 5, 11, 5] Output: true Explanation: Arrays can be split into [1, 5, 5] and [11]. Example 2: Input: [1, 2, 3, 5] Output: false Explanation: An array cannot be split into two elements and equal subsets.Copy the code

[D].

Subject analysis

  • Two elements and equal subsets, i.e. Sum- Sum [1]= Sum [1]= Sum [2]=Sum/2 for each subset, and all values are integers
  • So we can rule out the case where the sum of all elements is odd
  • The next question seems to be an easy oneAbstract as knapsack problemthe
    • Can you find a situation where there is a fixed number of n items with a total value? Can you find a situation where the selected items meet the items and are total/2

Idea 1: Dynamic planning

  • (TLE) (TLE) (TLE) (TLE

  • When it is difficult to imagine the DP equation at the first time, recursive method can be considered for parameter confirmation

  • When solving recursively, if solving forward, add one item at a time, and then determine whether the previous I can meet the maximum value of the requirement j (maximum value does not exceed j)

  • Therefore, the equation DP [I][j] can be defined to mean that the use of the first I elements does not exceed the maximum value of j

  • dp[i][j] = Math.max(dp[i – 1][j], j >= val ? dp[i – 1][j – val] + val : 0)

public boolean canPartition(int[] nums) {
            int total = 0;
            for (int n : nums
            ) {
                total += n;
            }
            //corner case
            if (total % 2! =0) {
                return false;
            }
            int target = total / 2 + 1;
            int[][] dp = new int[nums.length][target];
            // Initializes the boundary case, taking only all cases of the first element
            for (int i = 0; i < target; i++) {
                dp[0][i] = nums[0] < i ? nums[0] : 0;
            }
            for (int i = 1; i < nums.length; i++) {
                int val = nums[i];
                for (int j = 0; j < target; j++) {
                    // Select or unselect two states
                    dp[i][j] = Math.max(dp[i - 1][j], j >= val ? dp[i - 1][j - val] + val : 0); }}return dp[nums.length - 1][target - 1] == target - 1;
        }
Copy the code

Time complexity O(n+ N *total)

The optimization method of other dimensions is very similar to knapsack problem series 1

Optimize a dimension abstraction into odd and even

public boolean canPartition(int[] nums) {
            int total = 0;
            for (int n : nums
            ) {
                total += n;
            }
            //corner case
            if (total % 2! =0) {
                return false;
            }
            int target = total / 2 + 1;
            int[][] dp = new int[2][target];
            // Initializes the boundary case, taking only all cases of the first element
            for (int i = 0; i < target; i++) {
                dp[0][i] = nums[0] < i ? nums[0] : 0;
            }
            for (int i = 1; i < nums.length; i++) {
                int val = nums[i];
                for (int j = 0; j < target; j++) {
                    // Select or unselect two states
                    dp[i & 1][j] = Math.max(dp[(i - 1) & 1][j], j >= val ? dp[(i - 1) & 1][j - val] + val : 0); }}return dp[(nums.length-1) &1][target - 1] == target - 1;
        }
Copy the code

Optimize the abstraction of two dimensions into one dimension

public boolean canPartition(int[] nums) {
            int total = 0;
            for (int n : nums
            ) {
                total += n;
            }
            //corner case
            if (total % 2! =0) {
                return false;
            }
            int target = total / 2 + 1;
            int[] dp = new int[target];
            for (int i = 0; i < nums.length; i++) {
                int val = nums[i];
                for (int j = target - 1; j >= 0; j--) {
                    int no = dp[j];
                    // select item I
                    int yes = j >= val ? dp[j - val] + val : 0; dp[j] = Math.max(no, yes); }}return dp[target - 1] == target - 1; }}Copy the code

【 References 】

  • Gong Shui backpack problem sorting
  • Related Leetcode links