这个题目很有难度,解题思路大概分为两大步
第一步,算出可能的层数
第二步,利用递归来判断当前层数是否成立
其中第一步比较简单,以例题为例 3,6,6,3.总共四个数字
先将4个数字加起来 3+6+6+3 = 18
4个数字最多就是4层,其实是 3层,2层。先看 4层是否成立
18/4 结果不是整数,显然不行。 18/3 = 6 .而且6大于或等于所有元素,
说明3层是有希望的。同理 18/2=9 ,而且9大于或等于所有元素,说明9也是有希望的。
那么3层和2层都是候选层。这是第一步。
第二步稍微有点复杂。其实第二步的算法和力扣 698题, 划分为k个相等的子集是一样的,
可以参考力扣解法https://leetcode.cn/problems/partition-to-k-equal-sum-subsets/description/。
我这里的解法是将层数比作桶,比如三层,就相当于3个桶。4个数字就
相当于4个带分数的球。然后这4个球要放入3个桶,并且保证每个桶里面球的分数是6分。
具体代码如下
public class Demo102 {
public static void main(String[] args) {
int[] a = {3, 6, 6, 3, 6};
System.out.println(maxFloor(a));
}
public static int maxFloor(int[] a) {
int sum = 0;
// 算出所有元素的和
for (int i = 0; i < a.length; i++) {
sum = sum + a[i];
}
// 这个排序是为了 sum / i >= a[a.length - 1]的比较
Arrays.sort(a);
/* 计算可能的层数
* 比如有4个数,那我们依次假设可能的层数就是 4,3,2
* 然后再看假设是否可能成立
* sum % i == 0 看是否能整除
* sum / i >= a[a.length - 1] 平均值要等于或大于最大元素
*/
List<Integer> maybeFloors = new ArrayList<Integer>();
for (int i = a.length; i >= 2; i--) {
if (sum % i == 0 && sum / i >= a[a.length - 1]) {
maybeFloors.add(i);
}
}
if (maybeFloors.size() == 0) {
return -1;
}
for (int i = 0; i < maybeFloors.size(); i++) {
int k = maybeFloors.get(i);
//依次尝试每一层是否可能
if (canPartition(sum, a, k)) {
return k;
}
}
return -1;
}
public static boolean canPartition(int sum, int[] nums, int k) {
int average = sum / k;
int[] bucket = new int[k];
return canPartition(nums, 0, bucket, average);
}
public static boolean canPartition(int[] nums, int index, int[] bucket, int average) {
/*
* index == nums.length说明都放完了
* 如何证明都放完了的时候每个桶的数值恰好是average
* 反证法
* 首先 average * bucket.length = nums元素总和
* 根据程序逻辑
* 对于任意i,当 0<=i<bucket.length 必有bucket[i]<=average
* 取j, 且0<=j<bucket.length,如果bucket[j]<average
* 则必有bucket所有元素之和小于nums元素总和. 这和程序假定
* 所有元素都放入了bucket矛盾.
*/
if (index == nums.length) {
return true;
}
for (int i = 0; i < bucket.length; i++) {
// 多个桶分值一样,前面已经试了不要重复试,此处可能不好理解
if (i > 0 && bucket[i] == bucket[i - 1]) {
continue;
}
// 满足条件才能放入
if (bucket[i] + nums[index] <= average) {
// 放入
bucket[i] = bucket[i] + nums[index];
// 后续递归放入剩余的球
if (canPartition(nums, index + 1, bucket, average)) {
return true;
}
// 上面的策略失败了,就回退,继续尝试后面的策略
bucket[i] = bucket[i] - nums[index];
}
}
return false;
}
}