今天是第36天刷leetcode,立个flag,打卡60天。
算法挑战链接
416. 分割等和子集https://leetcode.cn/problems/partition-equal-subset-sum/
第一想法
题目理解:将一个数组分成两份,让两份之和相等。
这种题目下意识会使用回溯,因为尝试所有的结果是可以知道答案的。
但是回溯的代码会导致超时。
于是我就做不出来了。~~~~~~~
看完代码随想录之后的想法
代码随想录使用的是0-1背包的方式来解决这个问题的。(但是为什么用0-1背包呢?我没有想清楚。)
题目中给到的数组可以当成是物品,背包的容量是j。
题目的意思是:物品任取的情况下,是否可以恰好装满某个容量的背包。
因此可以套上0-1背包的公式去解决。
动态规划的五部曲走起:
- 确定dp数组(dp table)以及下标的含义
dp[j] 代表的含义是:在 0-i 物品任取的情况下,容量为 J 的最大价值
- 确定递推公式
递推公式就直接写了,因为是0-1背包的公式 dp[j] = max(dp[j], dp[j-i] + nums[i])
- dp的初始化
需要将dp数组全部初始化为0
- 确定遍历顺序
先遍历物品,然后在遍历容量,遍历容量的时候需要从大到小开始遍历,因为有每个物品只能使用一次的限制。
- 举例推导dp数组
数据就不推导了。
代码如下:
class Solution {
public boolean canPartition(int[] nums) {
if (nums.length <= 1) {
return false;
}
//计算总数
int sum = 0;
for (int num : nums) {
sum+=num;
}
//如果总数是奇数,不能平分
if (sum % 2 != 0) {
return false;
}
//dp[j] 表示在容量为j的情况下,价值最大
int medium = sum / 2;
int dp[] = new int[medium+1];
for (int i = 0; i < nums.length; i++) {
for (int j = medium; j >= nums[i]; j--) {
dp[j] = Math.max(dp[j], dp[j-nums[i]] + nums[i]);
}
}
return dp[medium] == medium;
}
}
实现过程中遇到哪些困难
不知道为啥可以使用0-1背包来解决这个问题(在没有做出来的时候)
今日收获
模版很重要,省事