You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

88 lines
2.7 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package class45;
import java.util.Arrays;
// 来自京东笔试
// 小明手中有n块积木并且小明知道每块积木的重量。现在小明希望将这些积木堆起来
// 要求是任意一块积木如果想堆在另一块积木上面,那么要求:
// 1) 上面的积木重量不能小于下面的积木重量
// 2) 上面积木的重量减去下面积木的重量不能超过x
// 3) 每堆中最下面的积木没有重量要求
// 现在小明有一个机会除了这n块积木还可以获得k块任意重量的积木。
// 小明希望将积木堆在一起,同时希望积木堆的数量越少越好,你能帮他找到最好的方案么?
// 输入描述:
// 第一行三个整数n,k,x1<=n<=2000000<=x,k<=1000000000
// 第二行n个整数表示积木的重量任意整数范围都在[1,1000000000]
// 样例输出:
// 13 1 38
// 20 20 80 70 70 70 420 5 1 5 1 60 90
// 1 1 5 5 20 20 60 70 70 70 80 90 420 -> 只有1块魔法积木x = 38
// 输出2
// 解释:
// 两堆分别是
// 1 1 5 5 20 20 (50) 60 70 70 70 80 90
// 420
// 其中x是一个任意重量的积木夹在20和60之间可以让积木继续往上搭
public class Code01_SplitBuildingBlock {
// 这是启发解
// arr是从小到大排序的x是限制固定参数
// 当前来到i位置积木重量arr[i]
// 潜台词 : 当前i位置的积木在一个堆里堆的开头在哪之前已经决定了
// i i+1 该在一起 or 该用魔法积木弥合 or 该分家
// 返回值arr[i....]最少能分几个堆?
public static int zuo(int[] arr, int x, int i, int r) {
if (i == arr.length - 1) {
return 1;
}
// i没到最后一个数
if (arr[i + 1] - arr[i] <= x) { // 一定贴在一起
return zuo(arr, x, i + 1, r);
} else { // 弥合!分家
// 分家
int p1 = 1 + zuo(arr, x, i + 1, r);
// 弥合
int p2 = Integer.MAX_VALUE;
int need = (arr[i + 1] - arr[i] - 1) / x;
if (r >= need) {
p2 = zuo(arr, x, i + 1, r - need);
}
return Math.min(p1, p2);
}
}
// 这是最优解
// arr里装着所有积木的重量
// k是魔法积木的数量每一块魔法积木都能变成任何重量
// x差值后 - 前 <= x
public static int minSplit(int[] arr, int k, int x) {
Arrays.sort(arr);
int n = arr.length;
int[] needs = new int[n];
int size = 0;
int splits = 1;
for (int i = 1; i < n; i++) {
if (arr[i] - arr[i - 1] > x) {
needs[size++] = arr[i] - arr[i - 1];
splits++;
}
}
if (splits == 1 || x == 0 || k == 0) {
return splits;
}
// 试图去利用魔法积木,弥合堆!
Arrays.sort(needs, 0, size);
for (int i = 0; i < size; i++) {
int need = (needs[i] - 1) / x;
if (k >= need) {
splits--;
k -= need;
} else {
break;
}
}
return splits;
}
}