LeetCode_416_分割等和子集

一、题目描述

给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
(nums[i]<=100;nums.length<=200)

示例:

输入:[1, 5, 11, 5]
输出:true
即数组分割为[1, 5, 5]和 [11]

输入:[1, 2, 3, 4]
输出:false

二、思路

最重要的是转换思想,即不去考虑这个数组到底能不能分成两个和相等的数组,而是考虑可不可以从这个数组中取一些元素,使得它们的和等于数组总和的一半。

转换思路后,可以直接使用动态规划解题。

确定状态:f[i][j]表示从0-i这些元素中是否可以组成j
转移方程:f[i][j] = f[i-1][j] || f[i-1][j-nums[j]],即两种情况,第一种为前i-1个元素即可组成 j,第二种情况为只有加入 i 后,才能组成 j。
边界条件:f[i][0] = true f[0][nums[0]] = true

三、代码

class Solution {
    public boolean canPartition(int[] nums) {
        //转换思路----数组中是否可以选择一部分元素,使得其和等于数组总的和的一半

        if(nums.length <2){
            return false;//只有一个元素
        }

        int length = nums.length;
        int sum = 0;
        int max = 0;
        //总和和最大元素值
        for(int i = 0;i<length;i++){
            sum += nums[i];
            max = Math.max(max,nums[i]);
        } 
        //如果总和为奇数,则不可能对半分
        if(sum %2 != 0){
            return false;
        }

        int target = sum/2;
        if(max > target){
            //最大元素大于总和的一半
            return false;
        }

        //确定状态---d[i][j]表示从前i个数字中,是否能组成j
        //转移方程---d[i][j] = d[i-1][j] || d[i - 1][j - nums[j]]
        //d[i-1][j]为不选取nums[i]的情况,即前i-1个元素也可以组成j
        //d[i-1][j - nums[i]]则是选取nums[i]的情况,即前i-1个元素组成j-nums[i],加上nums[i]后组成j
        //边界条件---d[i][0] = true  d[0][nums[0]] = true
        boolean[][] f = new boolean[length][target + 1];
        f[0][nums[0]] = true;
        f[0][0] = true;
        for(int i =1;i<length;i++){
            for(int j = 0;j<=target;j++){
                if(j==0){
                    f[i][0] = true;
                }else{
                   if(j>=nums[i]){
                       f[i][j] = f[i-1][j] || f[i - 1][j - nums[i]];
                   }else{
                       //当j < nums[i]时,只能看前i-1个数是否能凑出j来
                       f[i][j] = f[i-1][j];
                   }
                }
            }
        }
        return f[length-1][target];
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值