随想录Day43 | 1049. 最后一块石头的重量 II 、494. 目标和 | 动态规划

86 阅读2分钟

1049. 最后一块石头的重量 II

题目链接:1049. 最后一块石头的重量 II

思路:

这题的思路和416.分割等和子集类似,最优的情况是将石头分成两堆,每一堆的重量相同,都是总重量的一半。

动规五部曲 

1.确定dp数组以及下标的含义

dp[i][j]的定义为:在容量为j的情况下,从前i个石头中能取到的最大重量。

2.确定递推公式

状态转移方程 dp[i] = Math.max(dp[i - 1][j], dp[i - 1][j - stones[i]] + stones[i];

3.dp数组如何初始化

和01背包类似

4.确定遍历顺序

二维数组从右向左遍历

5.举例推导dp数组

class Solution {
    public int lastStoneWeightII(int[] stones) {
        int sum = 0;
        for (int i : stones) {
            sum += i;
        }
        int target = sum / 2;
        // dp数组的含义: 0 ~ i范围内任取数字,在容量为j的情况下,能取到的最大总和
        int[][] dp = new int[stones.length][target + 1];
        // 初始化
        for (int j = stones[0]; j <= target; j++) {
            dp[0][j] = stones[0];
        }

        for (int i = 1; i < stones.length; i++) {
            for (int j = 1; j <= target; j++) {
                if (j >= stones[i]) {
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - stones[i]] + stones[i]);
                } else {
                    dp[i][j] = dp[i - 1][j];
                }
            }
        }

        return (sum - dp[stones.length - 1][target]) - dp[stones.length - 1][target];
    }
}

494. 目标和

题目链接:494. 目标和

思路:
target值由数组的一部分数与另一部分数相减得到。
left - right = target, left + right = sum
left - (sum - left) = target
left = (sum + target) / 2
题目转换为装满大小为left的背包有多少种方法。

动规五部曲 

1.确定dp数组以及下标的含义

dp[j]的定义为:装满容量j的方法数量。

2.确定递推公式

dp[j] += dp[j - nums[i]];

3.dp数组如何初始化

dp[0] = 1

4.确定遍历顺序

一维数组从左向右遍历

class Solution {
    public int findTargetSumWays(int[] nums, int target) {
        int sum = 0;
        for (int i : nums) {
            sum += i;
        }
        if (Math.abs(target) > sum) return 0;
        if ((target + sum) % 2 != 0) return 0;
        int size = (target + sum) / 2;

        // dp的含义: dp[j]表示填满容量为j的包,有多少种方法
        int[] dp = new int[size + 1];
        // 初始化
        dp[0] = 1;
        for (int i = 0; i < nums.length; i++) {
            for (int j = size; j >= nums[i]; j--) {
                // 不拿nums[i]的情况下,填满容量为j的背包,有dp[j]种方法
                // 拿nums[i]的情况下,填满容量为j的背包,有dp[j - nums[i]]种方法
                dp[j] = dp[j] + dp[j - nums[i]];
            }
        }
        return dp[size];
    }   
}