• leetcode494 目标和(Medium)


    题目来源:leetcode494 目标和

    题目描述:

    给定一个非负整数数组,a1, a2, ..., an, 和一个目标数,S。现在你有两个符号 + 和 -。对于数组中的任意一个整数,你都可以从 + 或 -中选择一个符号添加在前面。

    返回可以使最终数组和为目标数 S 的所有添加符号的方法数。

    示例:

    输入:nums: [1, 1, 1, 1, 1], S: 3

    输出:5

    解释:
    -1+1+1+1+1 = 3
    +1-1+1+1+1 = 3
    +1+1-1+1+1 = 3
    +1+1+1-1+1 = 3
    +1+1+1+1-1 = 3

    一共有5种方法让最终目标和为3。
     
    提示:

    数组非空,且长度不会超过 20 。
    初始的数组的和不会超过 1000 。
    保证返回的最终结果能被 32 位整数存下。

    解题思路:

    参考讨论区:题解
    此问题可以转化为子集划分问题

    将一个集合划分成两个子集A,B, 问满足sum(A) - sum(B) = Target的分法有多少种

    两端同时加上集合元素和sum,得到2 * sum(A) = Target + sum ==> sum(A) = (Target + sum) / 2

    已知sum(A) = sum(B) + Target >= Target, sum = sum(A) + sum(B) >= sum(A)

    故sum >= Target, 且(Target + sum) % 2 == 0

    接下来就是一个求子序和为某值的子集数了, 也就是经典的01背包问题

    class Solution {
    public:
        int findTargetSumWays(vector<int>& nums, int S) {
            int sum=0;
            for(int i=0;i<nums.size();i++){
                sum+=nums[i];
            }
            if(sum<S||(sum+S)%2!=0){
                return 0;
            }
            else return subSets(nums,(sum+S)/2);
        }
        int subSets(vector<int> &nums,int sum){
            int n=nums.size(),i,j;
            vector<vector<int>> dp(n+1,vector<int>(sum+1,0));
            for(auto& v : dp) v[0] = 1;
            for(i=1;i<n+1;i++){
                int val=nums[i-1];
                for(j=0;j<=sum;j++){
                    if(j>=val){
                        dp[i][j]=dp[i-1][j]+dp[i-1][j-val];
                    }
                    else dp[i][j]=dp[i-1][j];
    
                }
            }
            return dp[n][sum];
        }
    };
    
  • 相关阅读:
    Rom定制
    android home键2
    蓝牙分享
    关闭系统锁屏
    android home键
    android view 背景重复
    android 找开软件所在市场页面
    jquery 选项卡
    ajaxfileupload ie 多参数
    找回 ie 图标
  • 原文地址:https://www.cnblogs.com/yjcoding/p/13653009.html
Copyright © 2020-2023  润新知