Featured image of post 416. 分割等和子集

416. 分割等和子集

题目描述

给你一个 只包含正整数非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

示例 1:

  • 输入:nums = [1,5,11,5]
  • 输出:true
  • 解释:数组可以分割成 [1, 5, 5] 和 [11] 。

示例 2:

  • 输入:nums = [1,2,3,5]
  • 输出:false
  • 解释:数组不能分割成两个元素和相等的子集。

提示:

  • 1 <= nums.length <= 200
  • 1 <= nums[i] <= 100

解法一:动态规划

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
func canPartition(nums []int) bool {
    n := len(nums)
    sum, maxNum := 0, 0

    for _, val := range nums {
        sum += val
        if val > maxNum {
            maxNum = val
        }
    }

    if sum&1 == 1 || maxNum > sum/2 {
        return false
    }

    dp := make([][]bool, n)
    w := sum/2 + 1
    for i := 0; i < n; i++ {
        dp[i] = make([]bool, w)
        dp[i][0] = true
    }
    dp[0][nums[0]] = true
    for i := 1; i < n; i++ {
        for j := 1; j < w; j++ {
            dp[i][j] = dp[i-1][j]
            if j >= nums[i] {
                dp[i][j] = dp[i][j] || dp[i-1][j-nums[i]]
            }
        }
    }
    return dp[n-1][w-1]
}

优化上述代码,使其空间复杂度从 O(n*(sum / 2)) 降到 O(sum / 2),优化后的代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
func canPartition(nums []int) bool {
    n := len(nums)
    sum, maxNum := 0, 0

    for _, val := range nums {
        sum += val
        if val > maxNum {
            maxNum = val
        }
    }

    if sum&1 == 1 || maxNum > sum/2 {
        return false
    }

    w := sum/2 + 1
    dp := make([]bool, w)
    dp[0] = true
    dp[nums[0]] = true
    for i := 1; i < n; i++ {
        // 注意:j 从 w - 1 开始,每次循环后减少 1
        // 而优化前的解法 j 从 0 开始,每次循环后增加 1
        for j := w - 1; j > 0; j-- {
            if j >= nums[i]{
                dp[j] = dp[j] || dp[j-nums[i]]
            }
        }
    }
    return dp[w-1]
}
Licensed under CC BY-NC-SA 4.0
最后更新于 2023/06/07 13:40:58
comments powered by Disqus
Built with Hugo
主题 StackJimmy 设计