这道题难在想到任意两块石头重量最小差转化为两堆石头的最小差,从而再联想到01背包问题。
如果你想到了将其转为两堆石头,那为什么又会想到背包问题呢?
思路:假设分为A、B两堆石头,A堆石头重量最大,B堆石头拿总重量减去A堆就得到它的最小重量,它们之间的差也就达到最小。
那A堆石头重量怎么达到最大呢?然后想到A堆石头重量有个理想的最大值,那就是总重量的一半。
而现在每块石头的重量又是不一样的,我们就有了一个目的,怎样分配那些石头去组成A堆,将其重量尽量往理想重量那里靠。
最后,你会发现,A堆石头就是一个背包,理想重量就是背包的容量,石头就是物品,怎样利用这些物品将背包赛的尽量满。
这不就形成了背包问题吗!
public int lastStoneWeightII(int[] stones) {
int sum = 0;
int n = stones.length;
for(int i : stones){
sum += i;
}
//背包的最大容量,也是一个石头堆理想的最大重量
int target = sum >> 1;
//背包的滚动数组
int[] dp = new int[target + 1];
for (int i = 0; i < n; i++) {
for (int j = target; j >= 1; j--) {
if(j >= stones[i]){
dp[j] = Math.max(dp[j], dp[j - stones[i]] + stones[i]);
}
//如果target容量的背包可以装满,那就无需往后执行了
//因为一堆石头的重量已经达到最大了,意味着另一堆石头重量达到最小,它们的差也达到最小
if(dp[j] == target) return sum % 2 == 0 ? 0 : 1;
}
}
//dp[target] 就是最后背包可以装的一个最大重量
//sum - dp[target] 就是另一堆石头的最小重量
return (sum - dp[target]) - dp[target]; //返回差值
}
当然,前提是你肯定要先搞懂01背包问题的思路是怎么样的。
我这里用的是一维滚动数组的方式,还有二维数组的方式。