【DP、Greedy】416. Partition Equal Subset Sum

Problem 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.

Note:

  • Each of the array element will not exceed 100.
  • The array size will not exceed 200.
Example 1:
Input: [1, 5, 11, 5]
Output: true
Explanation: The array can be partitioned as [1, 5, 5] and [11].
Example 2:
Input: [1, 2, 3, 5]
Output: false
Explanation: The array cannot be partitioned into equal sum subsets.

Problem-solving ideas:

Into equal subsets and easy to obtain the following properties:

  • If only one number, it certainly can not be divided;
  • If all numbers and is odd, certainly can not be divided;
  • The goal is to divide the sum of all divided by 2.
Method 1: Use greedy algorithm:
  • First of all were the number of descending order ;
  • Double pointer i, j; i points to the current number, j is moved backward;
  • Double loop, the outer loop a number i each time point, the inner loop during the movement of the j:
    1, and if the accumulated current <targets, and the update accumulation;
    2, and if the accumulated == target, True is returned;
    3, if the cumulative sum> target, then do nothing.
  • Finally, if you can not divide, returns False.

For example: nums = [10,8,7,6,5,4], for the first time the loop, i point 10, during traversal J, 8 and 10 can be loaded into, but not the latter figure; Second the loop, i points to 8, j during the traversal, 8,7 and 5 can be loaded into, and exactly equal to 20, True is returned.

Note: must be sorted in descending order, because we use a greedy strategy: Every first installed large, refillable times larger. If the load times larger than the target, it will continue to pick back third, fourth ... large, so it is feasible. However, if the sorting is not as nums = [4,5,6,7,8,10], taking the above-described method returns False.

The time complexity is O (n ^ 2), the spatial complexity is O (1).

Python3 achieve the following:
class Solution:
    def canPartition(self, nums):
        lens = len(nums)
        if lens == 1:
            return False
        tot = sum(nums)
        if tot % 2 == 1:
            return False
        target = tot // 2
        nums.sort(reverse=True)  # 从大到小排序
        for i in range(lens):
            tem = 0
            for j in range(i, lens):
                if tem + nums[j] == target:
                    return True
                elif tem + nums[j] < target:
                    tem += nums[j]
        return False

print(Solution().canPartition([6,5,4,8,10,7]))  # True
Method 2: Use Dynamic Solver:

In fact, this question is the application of 01- knapsack problem: 01- knapsack problem and its application .

We can be transformed into the following form: if there is a sub-element of the array and, and exactly equal to half of the original array elements of it? For each of the original array element has two states: (assuming the existence of this first sub-array) in sub-array which subarray inside or not. Such a view, we will be able to find the problem and knapsack problem is very similar, so we can use the solution to 0-1 knapsack problem solve road problems.

In question is present, each element of the original array which can be regarded as an article, the weight and value of items which are elements of the value; and a half of the original array may be considered as a maximum bearing weight of the backpack, when the backpack can lay down a maximum value of goods half of the original array and it returns true, false otherwise.

Therefore, we can easily get the following algorithm:

  • In this problem, knapsack and half the capacity of the array, it is necessary dp[len(nums)+1][sum(nums)//2+1]size of the array, where dp[i][j]represents the number placed before i j backpack capacity target value;
  • If j is less than the current capacity of the i-th, i.e. j <nums [i-1] , then dp[i][j] = dp[i-1][j];
  • Otherwise,dp[i][j] = max(dp[i-1][j], dp[i-1][j-nums[i-1]] + nums[i-1]) ;
  • When filling out each row of the table, you should determine what reaches the target value , that is, dp[i][j]whether it is True, rather than waiting for updates all rows in the table and then finished judgment;
  • If you have updated all the lines, dp[-1][-1]not equal to the target value, then can not be divided, it returns False.

The time complexity is O (n ^ 2), the spatial complexity is O (n * (sum (nums) // 2)).

Python3 achieve:
class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        lens = len(nums)
        if lens == 1:
            return False
        tot = sum(nums)
        if tot % 2 == 1:
            return False
        tar = tot // 2
        dp = [[0] * (tar+1) for _ in range(lens+1)]
        for i in range(1, lens + 1):
            for j in range(1, tar + 1):
                if j < nums[i-1]:
                    dp[i][j] = dp[i-1][j]
                else:
                    dp[i][j] = max(dp[i-1][j], dp[i-1][j-nums[i-1]] + nums[i-1])
            if dp[i][j] == tar:  # 更新完一行就应该判断一下
                return True
        return False

print(Solution().canPartition([2,5,3,4]))  # True
print(Solution().canPartition([5,1,3,5]))  # False

Note: this type of problem, namely items (array elements) there are two states in the presence or absence of the subject, it can be solved by thinking and solution 01- backpack.

Reproduced in: https: //www.jianshu.com/p/5f0a8a72a50f

Guess you like

Origin blog.csdn.net/weixin_34388207/article/details/91203971