数据结构学习 Leetcode494 目标和

关键词:动态规划 01背包 dfs回溯

一个套路:

  • 01背包:空间优化之后dp【target+1】,遍历的时候要逆序遍历
  • 完全背包:空间优化之后dp【target+1】,遍历的时候要正序遍历

题目:

解法一:

dfs 回溯

思路:

数组nums 的每个元素都可以添加符号+或-,因此每个元素有⒉种添加符号的方法,n个数共有2^n种添加符号的方法,对应2^n种不同的表达式。当n个元素都添加符号之后,即得到─种表达式,如果表达式的结果等于目标数target,则该表达式即为符合要求的表达式。
可以使用回溯的方法遍历所有的表达式,回溯过程中维护一个计数器count,当遇到一种表达式的结果等于目标数target时,将count的值加1。遍历完所有的表达式之后,即可得到结果等于目标数target的表达式的数目。

因为nums最多只有20,所以暴力的dfs应该是不会爆的。

回顾一下之前的dfs笔记吧!

中止条件:step>nums.size()

count统计符合个数

分出两个dfs,一个给+一个给-

复杂度计算:

时间复杂度O(2^n)

空间复杂度O(n)

代码:

class Solution {
public:
    int findTargetSumWays(std::vector<int>& nums, int target) {
        int count = 0, sum = 0;
        int step = 1;
        dfs(nums, target, step, sum, count);
        return count;
    }
    void dfs(std::vector<int>& nums, int target, int step, int sum, int& count)
    {
        if (step == nums.size() + 1)
        {
            if(sum == target)
                count++;
            return;
        }
        dfs(nums, target, step + 1, sum + nums[step - 1], count);
        dfs(nums, target, step + 1, sum - nums[step - 1], count);
        
    }
};

解法二:

动态规划 01背包

思路:

可以用非常巧的办法转换成用动态规划做。

 得到新的的目标为neg。

之后用01背包的知识就可以完成。

状态:dp[j]:前i个元素中,凑到目标j的方法总数。

转移方程:dp[j]=dp[j]+dp[j-nums[i]]

  • dp[j]:不需要第i个元素nums[i]的情况下,凑到目标j的方法总数。
  • dp[j-nums[i]]:需要第i个元素nums[i]的情况下,凑到目标j的方法总数。

初始条件:因为是计算总和所以设置为0

边界:dp[0]=1 前0个元素,凑到目标0的方法总数为1

复杂度计算:

时间复杂度O(nm) n=neg m=nums.size()

空间复杂度O(n) n=neg

代码:

class Solution {
public:
    int findTargetSumWays(std::vector<int>& nums, int target) {
        int sum = 0;
        for (const auto& x : nums)
            sum += x;
        int diff = sum - target;
        if (diff < 0 || diff & 1)
            return 0;
        int tar = diff / 2;
        std::vector<int> dp(tar + 1);
        //边界条件:当没有任何元素可以选取时,元素和只能是 0,对应的方案数是 1
        dp[0] = 1;//装0个重量,用0个装,一共有一种方法
        for (int i = 0; i < nums.size(); ++i)
        {
            for (int j = tar; j >= nums[i]; --j)
            {
                dp[j] += dp[j - nums[i]];
            }
        }
        return dp[tar];
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值