2022-01-16:小明手中有n块积木,并且小明知道每块积木的重量。现在小明希望将这些积木堆起来, 要求是任意一块积木如果想堆在另一块积木上面,那么要求: 1.上面的积木重量不能小于下面的积木重量; 2.上面积木的重量减去下面积木的重量不能超过x; 3.每堆中最下面的积木没有重量要求。 现在小明有一个机会,除了这n块积木,还可以获得k块任意重量的积木。 小明希望将积木堆在一起,同时希望积木堆的数量越少越好,你能帮他找到最好的方案么? 输入描述: 第一行三个整数n,k,x,1<=n<=200000,0<=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之间可以让积木继续往上搭。 来自京东面试。
答案2021-01-16:
先排序。假设没有魔法积木,求出堆数。然后求相邻堆需要的魔法积木数,魔法积木数从小到大弥合一次,堆数减1。 时间复杂度:排序的。 空间复杂度:O(N)。
代码用golang编写。代码如下:
package main
import (
"fmt"
"sort"
)
func main() {
arr := []int{20, 20, 80, 70, 70, 70, 420, 5, 1, 5, 1, 60, 90}
ret := minSplit(arr, 1, 38)
fmt.Println(ret)
}
func minSplit(arr []int, k, x int) int {
//Arrays.sort(arr);
sort.Ints(arr)
n := len(arr)
needs := make([]int, n)
size := 0
splits := 1
for i := 1; i < n; i++ {
if arr[i]-arr[i-1] > x {
needs[size] = arr[i] - arr[i-1]
size++
splits++
}
}
if splits == 1 || x == 0 || k == 0 {
return splits
}
// 试图去利用魔法积木,弥合堆!
//Arrays.sort(needs, 0, size);
sort.Ints(needs[0:size])
for i := 0; i < size; i++ {
need := (needs[i] - 1) / x
if k >= need {
splits--
k -= need
} else {
break
}
}
return splits
}
执行结果如下: