力扣 416. 分割等和子集

最近遇到很多动态规划的题,之前也有做过一些,但是对于一些细节还是无法掌握,所以打算多练习一点动态规划的题。

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

示例 1:

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

题目要得出的结论是:是否可以将数组分为两个元素和相等的子集,相当于计算一部分元素和,判断是否元素和可以等于总元素和的一半,又到了我们熟悉的选或不选的抉择。最简单暴力的还是dfs,就不写了,十有八九超时,直接按动态规划的思路去分析,可知以下结论。
1.计算出所有元素的和,若元素和为单数,则返回false,若元素中最大值,大于总元素和的一半,同样返回false;
2.转换公式:若选择当前元素,则值等于dp[i][j-nums[i]],选择的前提是j>=nums[i],若不选择,则值等于dp[i-1][j];
3.初始化:当target为0时,所有i都为true,因为可以不选择任何元素;当i为0时,只有num[0]的值为true,其他均为false。


万事俱备,码字。
 public boolean canPartition(int[] nums) {
        int sum = 0;
        int max = nums[0];
        for(int i : nums){
            sum+=i;
            max=Math.max(max,i);
        }
        if((sum&1)==1||max>sum>>1){
            return false;
        }
        int mid = sum>>1;
        int n = nums.length;
        boolean[][] dp = new boolean[n][mid+1];
        for(int i =0;i<n;i++){
            dp[i][0]=true;
        }
        dp[0][nums[0]]=true;
        for(int i=1;i<n;i++){
            for(int j = 1;j<=mid;j++){
                dp[i][j]=dp[i-1][j];
                if(j-nums[i]>=0){
                    dp[i][j]=dp[i][j]||dp[i-1][j-nums[i]];
                }
            }
        }
        return dp[n-1][mid];
    }

 

 

posted on 2021-06-13 22:33  jejas  阅读(42)  评论(0编辑  收藏  举报