leetcode之分割等和子集

题目详情:

在这里插入图片描述

1.回溯

根据这个题目,我们可以想到用回溯来做。加上这个数字或者减去这个数字,当最后结果为0时,则表示有一个结果。
代码可以是如下:

class Solution {
public:
    int result=0;
    int num=0;
    void dfs(vector<int>& nums,int i)
    {
        if(i==nums.size() )
        {
            if( num==0)result++;
            return ;
        }

        num+=nums[i];
        dfs(nums,i+1);
        num-=2*nums[i];
        dfs(nums,i+1);
        num+=nums[i];
    }
    bool canPartition(vector<int>& nums) {
        dfs(nums,0);
        return result;
    }
};

2.动态规划

思路:
这题可以转换为背包问题。设所有的元素和为sum,如果sum为奇数,则不可能将这个数组分割成两个元素和相等的集合。如果是偶数,则可以变成背包问题,在这个数组里面挑选出若干元素,使得和为sum/2。

(1)定义状态

设dp[i][j]为在前i个元素里面使得和为j的可能性,如果可能则为true,否则为false。dp是二维数组,设数组内共有m个元素,num=sum/2。则dp的大小为(m+1)*(num+1)。

(2)状态转移

(1)当nums[i-1]>j时,则dp[i][j]=dp[i-1][j]。(此时表示不能将第i个元素加入子集)
(2)当nums[i-1]<=j时,则dp[i][j]=dp[ i-1 ] [ j ] | dp[ i-1 ] [ j-nums[i-1] ]。此时表示将不把第i个元素假如集合和把第i个元素加入集合的可能性做一个或运算。

(3)临界条件

(1)当i=0,j=0时,为true.因为使用前0个元素和为0的可能性就是不用子集。
当i=0,j>0时,为false.因为当前0个元素和大于0是不可能的。
(2)当i>0,j=0时,为true.因为前i个元素和为0时,就是不选元素。

按照上述,则我们可以得到如下代码:

class Solution {
public:
    bool canPartition(vector<int>& nums) {
        int sum=0;
        for(int i=0;i<nums.size();i++)
        {
            sum+=nums[i];
        }
        if(sum%2!=0)return false;
        sum=sum/2;
        vector<vector<bool>>dp(nums.size()+1,vector<bool>(sum+1,0));
        dp[0][0]=true;
        for(int i=1;i<nums.size()+1;i++)
        {
            for(int j=0;j<sum+1;j++)
            {
                if (j >= nums[i - 1]) 
                {//不选第i个和选第i个元素
                    dp[i][j] = dp[i - 1][j] | dp[i-1][j - nums[i - 1]];
                }
                else 
                {//不能选择第i个元素
                    dp[i][j] = dp[i - 1][j];
                }
                if(j==sum&&dp[i][j]==true)
                {
                    return true;
                }
            }
        }
        return false;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值