1049. 最后一块石头的重量 II
题目链接:link
思路
这题在没有看题解时什么想法都没有,连暴露都不知道怎么写。看了题解后才恍然大悟,确实是动态规划,和 416. 分割等和子集合很像。
石头两两碰撞,那不就是可以均分成俩堆,然后俩堆互相碰撞,至于碰撞的过程可以不用考虑了。
代码
class Solution {
public int lastStoneWeightII(int[] stones) {
int n = stones.length;
int sum = 0;
for(int num : stones) {
sum += num;
}
int target = sum / 2;
int[] dp = new int[target + 1];
for(int i = 0; i < n; i++) {
for(int j = target; j >= stones[i]; j--) {
dp[j] = Math.max(dp[j], dp[j-stones[i]] + stones[i]);
}
}
return sum-dp[target]*2;
}
}
494.目标和
题目链接:link
思路
- 一开始想着,这题不是上一题一样吗都是分成两种情况?但是仔细想想,这题问的是表达式的数量,那就要记录下每种情况了,难度就又上去了。
先思考二维dp数组
的含义,这里由于求的是数量,那边数组的值可以假设为数量,显然i
表示第几个数,那么可以想到j表示当期的总和为j
,dp[i][j]
的含义是取到第i
个数时表达式的值为j
的数量。那么,最后的答案为dp[n][target]
。 - 这样想还是想的太少了,做了才发现没有考虑到负数的情况,数组下表为负直接就报错了,接下来就要继续思考如何避免负数的情况。目前可以知道最后表达式的值为
target
,所有数之和为sum
,那么有关系式正数之和-(sum-正数之和)= target
,从而可以知道如果最后表达式为target
,就必须所有的正数之和为(sum+targert)/2
。 - 从而本题变成了当表达式中正数之和为
(sum+targert)/2
时有几种情况。此时dp[i][j]
的含义为当取到第i
个数时正数之和为j
的表达式的数量为dp[i][j]
。
代码
class Solution {
public int findTargetSumWays(int[] nums, int target) {
int sum=0;
for(int i=0;i<nums.length;i++)
sum+=nums[i];
if ( target < 0 && sum < -target) return 0;
if ((target + sum) % 2 != 0) return 0;
int size = (target + sum) / 2;
if(size < 0) size = -size;
int max=Math.max(Math.max(size+1,sum+1),Math.abs(target)+1);
int[][] dp = new int[nums.length][max+1];
dp[0][nums[0]]=1;
dp[0][0]+=1;
for (int i = 1; i < nums.length; i++) {
for (int j = 0; j <=max; j++) {
if(j-nums[i]>=0){
dp[i][j]+=dp[i-1][j-nums[i]];
}
dp[i][j]+=dp[i-1][j];
}
}
// for(int i=0;i<nums.length;i++){
// for(int j=0;j<size+1;j++)
// {
// System.out.print(dp[i][j]+" ,");
// }
// System.out.println();
// }
return dp[nums.length-1][size];
}
}
总结
笑了,怎么会有这么多的问题,真的是苦了。
#474.一和零
题目链接:link
思路
这也太难了吧
代码
class Solution {
public int findMaxForm(String[] strs, int m, int n) {
//dp[i][j]表示i个0和j个1时的最大子集
int[][] dp = new int[m + 1][n + 1];
int oneNum, zeroNum;
for (String str : strs) {
oneNum = 0;
zeroNum = 0;
for (char ch : str.toCharArray()) {
if (ch == '0') {
zeroNum++;
} else {
oneNum++;
}
}
//倒序遍历
for (int i = m; i >= zeroNum; i--) {
for (int j = n; j >= oneNum; j--) {
dp[i][j] = Math.max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1);
}
}
}
return dp[m][n];
}
}