【leetCode-DFS】【leetCode-DP-01背包】279. 完全平方数

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

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

示例 1:

输入: 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位整数存下。

暴力搜索所有数+或-的状态

    private static int ccnt = 0;
    public static int findTargetSumWays(int[] nums, int S) {
        getSum(nums,0,S);
        return ccnt;
    }

    private static void getSum(int[] nums,int i,int S) {
        if(i == nums.length){
            if(0 == S){
                ccnt++;
            }
            return ;
        }

        getSum(nums,i + 1,S + nums[i]);
        getSum(nums,i + 1,S - nums[i]);
    }

优化

可以转化为01背包问题。

定义S(P)+ S(N) = C 其中S(p) 是集合中的正数集合 而S(N)是集合中的负数集合 而T是集合中的全部数据集
而 S(P)- S(N) = S(目标值) 其中 S是 目标值
S(P) - S(N) + (S(P)+ S(N) )  = S + (S(P)+ S(N) ) ==> 2S(P) = S+C ==> S(P) = (S+C) >> 1

定义:dp[i]代表遍历到数组第i个数的时候能组成目标数值的种类个数

初始化: dp[0] = 1

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

    public static int findTargetSumWays_OPT(int[] nums, int S) {
        
        int len = nums.length;
        int sum = 0;
        for(int  i = 0;i < len;i++) {
            sum += nums[i];
        }
        int tar = sum + S;
        if(tar % 2==1 || sum < S) {
            return 0;
        }
        tar /=2;
        int[] dp = new int[tar+1]; // 定义dp[i]为 第i个数的时候和为S的方法数
        dp[0] = 1;
        for(int i = 0;i < len;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、付费专栏及课程。

余额充值