zoukankan      html  css  js  c++  java
  • 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 };
  • 相关阅读:
    svn服务器安装
    flex 协同
    大尾端 小尾端
    UNIX下c语言的图形编程curses.h 函式库(2)
    vs2005设置
    client 连接 host —— 虚拟机
    fedora 连网问题。。
    pv ip uv
    checking for XML::Parser... configure: error: XML::Parser perl module is required for intltool
    UNIX下c语言的图形编程curses.h 函式库
  • 原文地址:https://www.cnblogs.com/fresh-coder/p/14404190.html
Copyright © 2011-2022 走看看