LeetCode 1049. 最后一块石头的重量II
题目链接:1049. 最后一块石头的重量 II - 力扣(LeetCode)
我们两部分考虑,一部分是正的,一部分是负的,这道题是想求最平衡的时候
每道题都要考虑dp五步:
1)确定dp数组下标与值的关系:其实就是求离target最近的一个和
2)确定递推公式:一维数组,所以从后向前,这样对于每个物品只会放一次。
3)确定初始值:dp[0][0]肯定是0,一点空间也没,一件物品也没,当然价值为0
4)确定遍历的数:
5)带入验证一下
代码:
#python 一维数组
class Solution:
def lastStoneWeightII(self, stones: List[int]) -> int:
total_sum = sum(stones)
target = total_sum // 2
dp = [0 for _ in range(target + 1)] //一维数组
dp[0] = 0
for stone in stones: //先遍历重量
for j in range(target, stone - 1, - 1):
dp[j] = max(dp[j], dp[j - stone] + stone) //比一比当前最大能装多少
return total_sum - 2 * dp[-1] //最后一个是最接近与中和的数
LeetCode 494. 目标和
题目链接:494. 目标和 - 力扣(LeetCode)
第一反应是一个DFS,回溯法,但是就别回了,直接DP,我们可以不断赋值,得到一个最大的表达式数组。
每道题都要考虑dp五步:
1)确定dp数组下标与值的关系:同样的就是求离target最近的一个和
2)确定递推公式:一维数组,所以从后向前,这样对于每个物品只会放一次。
3)确定初始值:dp[0]应该为1,此时只有一种选择
4)确定遍历的数:内循环从大到小
5)带入验证一下
代码:
#python
class Solution:
def findTargetSumWays(self, nums: List[int], target: int) -> int:
total_sum = sum(nums) # 计算nums的总和
if abs(target) > total_sum:
return 0 # 此时没有方案
if (target + total_sum) % 2 == 1:
return 0 # 此时没有方案
target_sum = (target + total_sum) // 2 # 目标和
dp = [0] * (target_sum + 1) # 创建动态规划数组,初始化为0
dp[0] = 1 # 当目标和为0时,只有一种方案,即什么都不选
for num in nums:
for j in range(target_sum, num - 1, -1):
dp[j] += dp[j - num] # 状态转移方程,累加不同选择方式的数量
return dp[target_sum] # 返回达到目标和的方案数
/java
class Solution {
public int findTargetSumWays(int[] nums, int target) {
int total_sum = 0;
for(int num : nums){
total_sum += num;
}
if(Math.abs(target) > total_sum){
return 0;
}
if((target + total_sum) % 2 == 1){
return 0;
}
int target_sum = (target + total_sum) / 2;
int[] dp = new int[target_sum + 1];
dp[0] = 1;
for(int num : nums){
for(int i = target_sum; i >= num; i--){
dp[i] += dp[i - num];
}
}
return dp[target_sum];
}
}
LeetCode 474. 一和零
题目链接:474. 一和零 - 力扣(LeetCode)
这道题感觉也是DFS,我们用DP来做,思路就是遍历所有的str,使用collections里的counter来计算一下1与0的个数,随后我们用一个二维数组dp[i][j]来得到一个子集元素最多的满足条件的子集,(i表示1的个数,j表示0的个数)。
每道题都要考虑dp五步:
1)确定dp数组下标与值的关系:
2)确定递推公式:二维数组,赋值的时候都是0,后面要求最大的,因此要么是当前的个数,要么是从前来的(dp[i - one_num][j - zero_num]从这里推过来,当然个数就要+1)
3)确定初始值:dp[0]应该为0
4)确定遍历的数:都是逆向的,其实这和前面的题目有点像,像两个内循环
d5)带入验证一下
代码:
#python
class Solution:
def findMaxForm(self, strs: List[str], m: int, n: int) -> int:
dp = [[0 for _ in range(n + 1)] for _ in range(m + 1)]
for st in strs:
one_num = st.count('1') //1的个数
zero_num = len(st) - one_num //0的个数
for i in range(m, zero_num - 1, -1): //逆向
for j in range(n, one_num - 1, - 1): //逆向
dp[i][j] = max(dp[i][j], dp[i - zero_num][j - one_num] + 1)
return dp[m][n]
/java
class Solution {
public int findMaxForm(String[] strs, int m, int n) {
int[][] dp = new int[m + 1][n + 1];
for(String str : strs){
char[] words = str.toCharArray();
int one_sum = 0, zero_sum = 0;
for(char word : words){
if(word == '1'){
one_sum++;
}else{
zero_sum++;
}
}
for(int i = m; i >= zero_sum; i--){
for(int j = n; j >= one_sum; j--){
dp[i][j] = Math.max(dp[i][j], dp[i - zero_sum][j - one_sum] + 1);
}
}
}
return dp[m][n];
}
}