Partition Equal Subset Sum

探讨如何通过动态规划解决等和子集划分问题,给出两种方法:一种使用二维DP数组,另一种采用DFS结合缓存策略。适用于面试准备和技术交流。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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:

  1. Each of the array element will not exceed 100.
  2. 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.

01背包问题 也就是一个array里面,能否背到sum / 2的重量;

dp[i][j]的物理意义是:我走到第i个物品,我是否取得j的重量;

class Solution {
    public boolean canPartition(int[] nums) {
        int totalsum = 0;
        for(int num: nums) {
            totalsum += num;
        }
        if(totalsum % 2 != 0) {
            return false;
        }
        int n = nums.length;
        boolean[][] dp = new boolean[n + 1][totalsum / 2 + 1];
        // dp[i][j] , move ith position, whether or not i can get j amount;
        dp[0][0] = true;
        // 1st row;
        for(int j = 1; j < dp[0].length; j++) {
            dp[0][j] = false;
        }
        // 1st col;
        for(int i = 1; i < dp.length; i++) {
            dp[i][0] = true;
        }
        // calculate matrix;
        for(int i = 1; i < dp.length; i++) {
            for(int j = 1; j < dp[0].length; j++) {
                dp[i][j] = dp[i - 1][j]; // not pick up;
                if(j - nums[i - 1] >= 0) {
                    dp[i][j] |= dp[i - 1][j - nums[i - 1]];
                }
            }
        }
        return dp[n][totalsum / 2];
    }
}

思路2:这题是 Partition to K Equal Sum Subsets 的简化版,如果用DFS暴力求,会超时,那么就需要用cache来加速;

dp[i][cursum] 代表的物理意义是:我走到ith 元素,能够达到的cursum的情况下,能否最后走到target,因为dfs从0,0开始,一直走到num.length 和target sum之后,return base case,然后回来,所以cache只是记录中间结果,所以代表能够reach target, true or false;

加cache提速:这里比较巧妙的是用Boolean  ojbect数组来记录,如果!= null,return结果;

class Solution {
    public boolean canPartition(int[] nums) {
        if(nums == null || nums.length == 0) {
            return false;
        }
        int sum = 0; int maxnum = 0;
        for(int num : nums) {
            sum += num;
            maxnum = Math.max(maxnum, num);
        }
        if(sum % 2 != 0 || maxnum > sum / 2) {
            return false;
        }
        Boolean[][] dp = new Boolean[nums.length][sum / 2 + 1];
        boolean[] visited = new boolean[nums.length];
        return dfs(nums, visited, sum / 2, 0, 0, dp);
    }
    
    private boolean dfs(int[] nums, boolean[] visited, int target, int cursum, int index,
                       Boolean[][] dp) {
        if(cursum == target) {
            return true;
        }
        if(index == nums.length || cursum > target) {
            return false;
        }
        if(dp[index][cursum] != null) {
            return dp[index][cursum];
        }
        for(int i = index; i < nums.length; i++) {
            if(visited[i]) {
                continue;
            }
            if(cursum + nums[i] <= target) {
                visited[i] = true;
                if(dfs(nums, visited, target, cursum + nums[i], i + 1, dp)) {
                    dp[i][cursum] = true;
                    return true;
                }
                visited[i] = false;
            }
        }
        dp[index][cursum] = false;
        return dp[index][cursum];
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值