京东笔试题
题目: 现在又n块积木,小明知道每块的重量,任意一个积木要想堆在另一个积木上:
条件:1.上面的积木重量大于下面积木的重量
2.上面的积木重量 减去 下面的积木重量 不超过x
3.最下面的积木重量没有要求
现在小明有n个积木,小明还可以获得k个魔法积木(可以变成任意重量),小明希望尽可能多的积木堆在一起,找出最好方法。
[7,4,1,9,13] x = 3, k = 0 两堆 (第一堆是1,4,7,9 ;第二堆是13)
思路:先不考虑魔法积木,则解法应该为将数组arr排序(1,4,7,9,13)依次垒上(不超过x)
现在又有k个魔法积木,我们可以使得9和13之间相容 变为一堆。
如:arr = [1,3,7,9,11,11,25,27,59] ; x = 3; k = 4;
不考虑魔法积木:
第一堆:[1,3]
第二堆:[7,9,11,11]
第三堆:[27,27]
第四堆:[59]
现在魔法积木如果融合一二堆:需要一块(7 - 3)
如果融合二三堆:需要四块(25 - 11 = 14; 四块分别是14,17,20,23)
如果融合三四堆:需要更多块
反正不管我们融合哪辆堆,堆的数量都是减一,既然收益相同,我们要选择代价最低的即融合一二堆。
代码:
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; //needs数组的长度
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可以融合,堆得数量减一
k -= need; //魔法积木也减去相应的个数
} else {
break;//魔法积木数量不够,因为升序所以直接退出循环
}
}
return splits;
}