【力扣刷题 | 第二十四天】

【力扣刷题 | 第二十四天】_第1张图片

目录

前言:

1049. 最后一块石头的重量 II - 力扣(LeetCode)

494. 目标和 - 力扣(LeetCode)

总结:


前言:

                 今天我们依然暴打动态规划

1049. 最后一块石头的重量 II - 力扣(LeetCode)

有一堆石头,用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。

每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为 x 和 y,且 x <= y。那么粉碎的可能结果如下:

如果 x == y,那么两块石头都会被完全粉碎;
如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为 y-x。
最后,最多只会剩下一块 石头。返回此石头 最小的可能重量 。如果没有石头剩下,就返回 0。

【力扣刷题 | 第二十四天】_第2张图片

这个问题其实很好想:我们如何把石头尽可能的撞碎呢?

很简单,我们在大体上把这些石头分成重量相似的两堆,因为如果两堆石头的重量相似,那么相撞后就一定会得到最小的值。

因此从动态分类的角度来讲,我们可以把这道题理解为是  一个重量为(sum/2)的背包,我们尽可能的装背包,之后装进背包的是一堆石头,未装进背包的是一堆石头,那么这两堆石头相减,就可以得到最小的石头重量。

那么我们就又把这道题转化为了 装与不装的01背包问题

其实这道题和我们前天做的分割等和子集是基本相同的,感兴趣的朋友可以去看一下那道题

那么既然是动态规划问题,我们就继续进行动态规划五部曲:

1.确定dp数组及其含义:dp[j]  是背包含量为j的时候所背的最大价值(在这里我们重量就是价值,价值就是重量)

2.递推公式  dp[j] = max(dp[j] , dp[ j - stones[i] ]+stones[i])

里层的减是减去容量,外面的加是加上价值,只不过是因为我们的重量和价值是一样的

3.确定初始化:全部初始化为0即可 

class Solution {
public:
    int lastStoneWeightII(vector& stones) {
            int sum=0;
            vectordp(1501,0);
        for(int a : stones)
        {
            sum=sum+a;
        }

        int target = sum/2;

        for(int i=0;i=stones[i];j--)
            {
                 dp[j] = max(dp[j] , dp[ j - stones[i] ]+stones[i]);
            }
        }
        return sum-dp[target]-dp[target];
    }
};

 在这里我们要特别对末尾进行说明,为什么是   return sum-dp[target]-dp[target];

其实很好理解,因为这里的dp数组是一堆石头,而我们用sum-dp数组就得到了另外一堆石头的重量,再减一次dp数组,实际就是模拟两堆石头进行碰撞。

494. 目标和 - 力扣(LeetCode)

给你一个非负整数数组 nums 和一个整数 target 。

向数组中的每个整数前添加 '+' 或 '-' ,然后串联起所有整数,可以构造一个 表达式 :

例如,nums = [2, 1] ,可以在 2 之前添加 '+' ,在 1 之前添加 '-' ,然后串联起来得到表达式 "+2-1" 。
返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目。

【力扣刷题 | 第二十四天】_第3张图片

这道题其实我们可以这样理解: 

一共有两个集合,两个集合分别装数字,设置目标值target,询问有几种可能使得两个集合相减的数字等于target

再优化一下:

我们可以把target也作为一个数字加到这两个集合的待选序列,询问有几种可能  使得两个集合的值相等

  再转化一下思维:

,而target只有一个,也就是只能永远出现在一侧,另外一侧始终没有target,那么我们始终求没有target的那一侧不就好了嘛,换句话说,不就是在给定集合里面寻找有多少个集合的值等于(sum+target)/2/

那么我们不就又把这道题转化为了背包问题嘛?只不过以前我们总是在求是否有一种方法能把背包装满,现在求的是有多少种方法把背包装满。

因此我们按照动态规划五部曲走:

1.确定dp数组的含义:dp[j] 表示填满容量为j的背包最多有dp[j]种方法,例如dp[2]是指填满容量为2的背包最多有dp[2]种方法。

2.确定递推公式:dp[j]+=dp[j-nums[i]];

class Solution {
public:
    int findTargetSumWays(vector& nums, int target) {
        int sum=0;
        for(int a : nums)
        {
            sum=sum+a;
        }

        if((target + sum)%2==1) return 0;
        if(abs(target)>sum) return 0;
        else
        {
              int a = (target + sum) / 2;
              vector dp(a + 1, 0);
             dp[0] = 1;
            for (int i = 0; i < nums.size(); i++) 
            {
               for (int j = a; j >= nums[i]; j--) 
               {
                dp[j] += dp[j - nums[i]];
                }
            }
        return dp[a];
        }
    }
};

总结:

        动态规划想清楚之后直接爆杀。

如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力!

 

你可能感兴趣的:(【力扣刷题】,leetcode,算法,职场和发展)