分割等和子集

题目链接

分割等和子集

题目描述

分割等和子集_第1张图片

注意点

  • 数组 nums 非空
  • 数组 nums 只包含正整数

解答思路

  • 最初想到的是根据回溯+剪枝解决本题,如果数组大小小于2,则肯定不能找到分割等和子集,除此以外,如果数组之和sum不能被2整除,也肯定不能找到分割等和子集,然后将数组排序后深度优先遍历查找符合的组合,最终运行时超时了,要考虑更加巧妙的方法
  • 参照题解使用动态规划完成本题,其可以转换成背包问题,思路为:创建一个dp[n][target + 1]的数组,其中n为数组的长度,target为数组之和除以2,dp[i][j]表示(0, i)范围内能否选出某个数字组合之和为j,从dp[0][0]开始,找到从0~i个元素取数字组合时所有可能组成的数字之和的值,并将相应dp[i][j]更新为1,直到找到dp[i][target]为true或遍历完整个数组为止

代码

class Solution {
    public boolean canPartition(int[] nums) {
        int n = nums.length;
        if (n < 2) {
            return false;
        }
        int sum = 0;
        for (int num : nums) {
            sum += num;
        }
        if (sum % 2 != 0) {
            return false;
        }
        int target = sum / 2;
        // dp[i][j]表示(0, i)范围内能否选出某个数字组合之和为j
        boolean[][] dp = new boolean[n][target + 1];
        // 和为0必定成立
        for (int i = 0; i < n; i++) {
            dp[i][0] = true;
        }
        for (int i = 0; i < n; i++) {
            // 该元素为一组成立
            if (nums[i] == target) {
                return true;
            }
            // 第一个元素不必考虑前面(0, i - 1)的数字组合
            if (i == 0) {
                if (nums[i] < target) {
                    dp[i][nums[i]] = true;
                }
                continue;
            }
            // 根据前面(0, i - 1)的数字组合推出(0, i)的数字组合之和
            for (int j = 1; j <= target; j++) {
                if (dp[i - 1][j] && j + nums[i] == target) {
                    return true;
                }
                dp[i][j] = dp[i - 1][j];
                if (nums[i] < j) {
                    dp[i][j] = dp[i][j] || dp[i - 1][j - nums[i]];
                }
            }
        }
        return false;
    }
}

关键点

  • 将本题转换为背包问题
  • 动态规划的思想
  • 本题如何通过前面的情况动态规划推出后面的情况

你可能感兴趣的:(算法TOP100,leetcode,java,算法,数据结构,动态规划)