• LeetCode494. 目标和


    题目

    分析

    这道题开始我是想用回溯,但一看数据量,肯定会超时(指数级的时间复杂度)。没有思路,想着应该是dp,怎么进行转化,转为我们熟悉的问题呢?题目的意思就是说将数组分成两堆n1,n2,使得 n1 - n2 = S 。且有n1 + n2 = sum。由这两个式子可得 n1 + n2 = 2 * n2 + S = sum。=》 n2 = (sum - S) / 2。这样我们可看出了也就是找到一个子集合,使得集合之和等于(sum - S) / 2的方法有多少种?这里我们可能还是会想回溯暴搜比如LeetCode 39组合之和,这里也可用dp来做。由于每个数只能用一次,这就转换为01背包问题。直接用二维dp熟悉了,直接用一维dp来做。dp[j] 表示容量为j 有多少种方案。怎么推导动态转移方程呢?还是仿照01背包问题的思想。就是用集合的思想,先去再加。

     dp[j] += dp[j-nums[i]]——这也是求组合问题常用的转移方程。

    注意:初始化时,dp【0】要为1,若为0,则dp数组全为0。这里1可以理解为容量0啥也不装,为1种方案。

    代码

     1 class Solution {
     2 public:
     3     int findTargetSumWays(vector<int>& nums, int S) {
     4         int sum = 0;
     5         for(auto s:nums){
     6             sum += s;
     7         }
     8         if(sum < S) return 0; //边界
     9         int t = (sum - S);
    10         if(t%2) return 0;  //奇数没有方案
    11         vector<int>dp(t/2+1,0);
    12         dp[0] = 1;//初始化为1,容量为0时装0件物品,一种方案,若为0,则全部为0
    13         for(int i = 0;i < nums.size();i++){
    14             for(int j = t / 2;j >= nums[i];j--){
    15                 dp[j] += dp[j-nums[i]];
    16             }
    17         }
    18         return dp[t/2];
    19     }
    20 };

    时间复杂度O(n*m),n为背包个数,m为背包容量。

    空间复杂度O(m)

    回溯法代码

     1 class Solution {
     2     vector<vector<int>>res;
     3     vector<int>path;
     4     void backtracking(vector<int>nums,int target,int sum,int startIndex){
     5         if(sum == target){
     6             res.push_back(path);
     7         }
     8         for(int i = startIndex;i < nums.size() && nums[i] + sum <= target;i++){
     9             //做剪枝,如果nums[i] + sum > target直接终止
    10             path.push_back(nums[i]);
    11             sum += nums[i];
    12             backtracking(nums,target,sum,i+1);
    13             sum -= nums[i];
    14             path.pop_back();
    15         }
    16     }
    17 
    18 public:
    19     int findTargetSumWays(vector<int>& nums, int S) {
    20         int sum = 0;
    21         for(auto s:nums){
    22             sum += s;
    23         }
    24         if(sum < S) return 0;
    25         int t = (sum - S);
    26         if(t%2) return 0;  //奇数没有方案
    27         //用回溯来代替dp
    28         sort(nums.begin(),nums.end()); //回溯中存在剪枝要先排序
    29         backtracking(nums,t/2,0,0);
    30         return res.size();
    31     }
    32 };
  • 相关阅读:
    【IHttpHandler】在ASP.Net2.0中使用UrlRewritingNet实现链接重写
    【IHttpHandler】IHttpModule实现URL重写
    【IHttpHandler】使用IHttpHandler防盗链
    【IHttpHandler】HttpModule,HttpHandler,HttpHandlerFactory简单使用
    【IHttpHandler】HttpModule的认识
    【IHttpHandler】了解 IHttpHandler
    【MVC】ASP.NET MVC 请求生命周期
    【MVC】ASP.NET MVC HtmlHelper用法大全
    【MVC】ASP.NET MVC中实现多个按钮提交的几种方法
    【MVC】自定义ASP.NET MVC Html辅助方法
  • 原文地址:https://www.cnblogs.com/fresh-coder/p/14404190.html
Copyright © 2020-2023  润新知