zoukankan      html  css  js  c++  java
  • 目标和 动态规划

    1. 题目描述

    给定一个非负整数数组,a1, a2, ..., an,和一个目标数S。现在你有两个符号+-。对于数组中的任意一个整数,你都可以从+-中选择一个符号添加在前面。
    返回可以使最终数组和为目标数S的所有添加符号的方案数。
    提示:

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

    示例:

    输入: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。
    

    2. 题解

    这道题是一个常见的背包问题,我们可以用类似求解背包问题的方法来求出可能的方案数。
    我们用dp[i][j]表示用数组中的前i个元素,组成和为j的方案数。

    public int findTargetSumWays(int[] nums, int S) {
    	int[][] dp = new int[nums.length][2001];
    	dp[0][nums[0] + 1000] = 1;
    	dp[0][-nums[0] + 1000] += 1;
    	for (int i = 1; i < nums.length; i++) {
    		for (int sum = -1000; sum <= 1000; sum++) {
    			if (dp[i - 1][sum + 1000] > 0) {
    				dp[i][sum + nums[i] + 1000] += dp[i - 1][sum + 1000];
    				dp[i][sum - nums[i] + 1000] += dp[i - 1][sum + 1000];
    			}
    		}
    	}
    	return S > 1000 ? 0 : dp[nums.length - 1][S + 1000];
    }
    

    注意到数组下标不能为负数,由于题目要求数组和不超过1000,所以需要给dp[i][j]的第二维预先增加1000

    nums: [2, 1, 1, 2], S: 0为例,这里给dp[i][j]的第二维预先增加6,因为该数组和不超过6

    public int findTargetSumWays(int[] nums, int S) {
    	int[][] dp = new int[nums.length][13];
    	dp[0][nums[0] + 6] = 1;
    	dp[0][-nums[0] + 6] += 1;
    	for (int i = 1; i < nums.length; i++) {
    		for (int sum = -6; sum <= 6; sum++) {
    			if (dp[i - 1][sum + 6] > 0) {
    				dp[i][sum + nums[i] + 6] += dp[i - 1][sum + 6];
    				dp[i][sum - nums[i] + 6] += dp[i - 1][sum + 6];
    			}
    		}
    	}
    	return S > 6 ? 0 : dp[nums.length - 1][S + 6];
    }
    


    dp[0][2 + 6]表示用数组中的前0个元素,组成和为8的方案数。因为dp[i][j]的第二维预先增加6,所以实际上dp[0][2 + 6]表示用数组中的前0个元素,组成和为2的方案数。
    因此,这里dp[3][6]表示用数组中的前3个元素(包含4个元素),组成和为0的方案数,即dp[3][0 + 6]
    解释代码:
    nums[0]+nums[0]-nums[0]两种情况,接着遍历nums[1]
    由于dp[0][-2 + 6] = 1 > 0,所以dp[1][-2 + 1 + 6] += dp[0][-2 + 6]dp[1][-2 - 1 + 6] += dp[0][-2 + 6]
    接着遍历nums[2],同理,dp[2][-3 + 1 + 6] += dp[1][-3 + 6]dp[2][-1 - 1 + 6] += dp[1][-1 + 6]
    dp[2][-2 + 6]表示用数组中的前2个元素,组成和为-2的方案数为2(-2+1-1-2-1+1)。
    这里dp[2][-2 + 6]先加dp[1][-3 + 6],再加dp[1][-1 + 6],所以要用+=来累加方案数。

    参考:

  • 相关阅读:
    jvisualm 结合 visualGC 进行jvm监控,并分析垃圾回收
    linux 查看服务器cpu 与内存配置
    arthas 使用总结
    selinux contexts 安全上下文的临时更改
    Android 8.1 Doze模式分析(五) Doze白名单及Debug方式
    Window 任意窗口置顶软件Window TopMost Control
    Android ApkToolPlus一个可视化的跨平台 apk 分析工具
    SVN Please execute the 'Cleanup' command.
    Android 如何在64位安卓系统中使用32位SO库
    Android cmd命令查看apk是32位还是64位?
  • 原文地址:https://www.cnblogs.com/gzhjj/p/14171494.html
Copyright © 2011-2022 走看看