题解 | #农场的奶牛分组II# java
农场的奶牛分组II
https://www.nowcoder.com/practice/ae745225d12f44ca9e84486d051edbfa
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param weights int整型一维数组
* @return bool布尔型
*/
public boolean canPartitionII (int[] weights) {
// write code here
int n = weights.length;
int s = Arrays.stream(weights).sum();
if (s % 3 != 0 || n < 3)
return false;
int target = s / 3;
int[][] f = new int[n + 1][target + 1];
for (int i = 1; i <= n; ++i) {
for (int j = target; j >= weights[i - 1]; --j) {
f[i][j] = Math.max(f[i - 1][j], f[i - 1][j - weights[i - 1]] + weights[i - 1]);
}
}
if (f[n][target] != target)
return false;
int left = target;
for (int i = n; i >= 1; --i) {
if (left >= weights[i - 1] &&
f[i - 1][left - weights[i - 1]] == left - weights[i - 1])
left -= weights[i - 1];
}
return left == 0;
}
}
该代码使用的编程语言是Java。
题目是一个背包问题的变形,要判断是否能将一个整数数组分割成两个子集,使得两个子集的元素和相等。具体思路如下:
- 首先计算整个数组的元素和s,如果s不能被3整除或者数组长度小于3,则无法分割成两个和相等的子集,直接返回false。
- 将问题转化为在数组中找到是否存在和为s/3的子集。
- 使用动态规划解决该问题,采用二维数组f,其中f[i][j]表示前i个元素中能否组合出和为j。初始时,将f数组初始化为0。
- 遍历数组中的每个元素weights[i],从target到weights[i]进行递减遍历,更新f数组,计算最大的子集和。如果weights[i]大于j,则当前元素无法放入子集中,继承上一个状态,即f[i][j] = f[i-1][j]。否则,可以选择将weights[i]放入子集或者不放入子集,取两者中的较大值,即f[i][j] = max(f[i-1][j], f[i-1][j-weights[i]] + weights[i])。
- 如果f[n][target]不等于target,说明无法找到子集的和为s/3,返回false。
- 否则,继续判断剩余的数组元素能否组合成和为s/3的子集。从n到1进行递减遍历,如果剩余的和等于weights[i-1],则将left减去weights[i-1]。
- 最后返回left是否等于0,如果等于0,则说明存在两个和相等的子集,返回true;否则,返回false。
这样,通过动态规划的方式,可以高效地解决该问题。
查看3道真题和解析