问题陈述
掉蛋指的是一类问题,在这些问题中,在不超过(低)数量的某些失效状态的情况下找到正确的响应非常重要。在一个玩具的例子中,有一个地板塔和一个理想蛋的蛋滴管。理想蛋的物理特性是,如果它从地板或以上掉落,它将会破碎,如果从地板或下面掉落,它将不会受到任何损害。问题是要找到一种策略,使蛋滴管能够尽可能少地确定蛋底。此问题在现实世界中有许多应用程序,例如避免调用慢速HDD,或尝试最小化缓存未命中,或在数据库上运行大量昂贵的查询。
Problem Statement and Solution Analysis
当我们有N个鸡蛋和K个楼层时,下面的代码使用时间复杂度为 O(N)的二次方程找到最小滴数。
(function() {
var eggs = 3, floors = 2;
function findFloor(eggs, floors) {
if (eggs === 1 || floors === 0 || floors === 1) {
return floors;
}
var minDrops = Math.ceil((-1 + Math.sqrt(1 + (8 * floors))) / 2);
return Math.min(minDrops, findFloor(eggs - 1, minDrops));
}
console.log(findFloor(eggs, floors));
})();
我已经测试了一些测试用例,但有人可以建议,这适用于所有场景吗?
答案 0 :(得分:1)
不,这并不总能产生正确的结果。您已使用此公式:
但是,如果鸡蛋的数量是两个,那么该公式只能提供有意义的结果。注意鸡蛋的数量是如何出现的,只有楼层的数量( k )。
以4层3鸡蛋为例。你的函数返回2,但如果这是正确的答案,那么你会在这两次尝试中选择哪一层?
让我们从3楼掉下来:鸡蛋休息。然后从地板1扔:鸡蛋不会破裂。现在我们不知道答案是1楼还是2楼。我们需要再放一个鸡蛋才能确定。
也许从2楼开始?:鸡蛋还可以。然后从4楼扔蛋:鸡蛋休息。现在我们不知道答案是2楼还是3楼。我们需要再放一个鸡蛋才能确定。
所以,在最坏的情况下,我们需要至少掉落3个鸡蛋。
您的算法不正确。您引用的文章有两个正确的实现(尽管有一些带有变量名称的拼写错误)。这里是JavaScript:
function getNumDropsRecursive(eggs, floors) {
if (eggs == 1 || floors == 0 || floors == 1) {
return floors
}
let minimum = Infinity;
for (let floor = 1; floor <= floors; floor++) {
minimum = Math.min(
minimum,
1 + Math.max(getNumDropsRecursive(eggs - 1, floor - 1),
getNumDropsRecursive(eggs, floors - floor))
)
}
return minimum;
}
function getNumDropsDP(eggs, floors) {
const numdrops = [
null,
[...Array(floors+1).keys()],
...Array.from(Array(eggs-1), _ => [0, 1])
];
for (let remainingEggs = 2; remainingEggs <= eggs; remainingEggs++) {
for (let choices = 2; choices <= floors; choices++) {
let minimum = Infinity;
for (let dropAt = 1; dropAt <= choices; dropAt++) {
minimum = Math.min(minimum,
1 + Math.max(numdrops[remainingEggs-1][dropAt-1],
numdrops[remainingEggs][choices-dropAt])
);
}
numdrops[remainingEggs][choices] = minimum;
}
}
return numdrops[eggs][floors];
}
不建议使用第一个,因为它在20以上的参数开始变得非常慢。
我还会以不同的方式命名您的功能。该功能找不到楼层,但在最坏的情况下,您需要丢弃的数量才能找到楼层。所以像getNumDrops
这样的名字会更有说服力。
答案 1 :(得分:0)
我相信已知的solution是O(n log k)
。以下是一些不匹配:
/*
W(n,k) = 1 + min{max(W(n − 1, x − 1), W(n,k − x)): x = 1, 2, ..., k }
with W(n,0) = 0 for all n > 0 and W(1,k) = k for all k.
*/
function f(n,k){
if (k == 0 && n > 0)
return 0;
if (n == 1)
return k;
let best = Infinity;
for (let x=1; x<=k; x++)
best = Math.min(best, Math.max(f(n-1, x-1), f(n, k-x)));
return 1 + best;
}
function findFloor(eggs, floors) {
if (eggs === 1 || floors === 0 || floors === 1) {
return floors;
}
var minDrops = Math.ceil((-1 + Math.sqrt(1 + (8 * floors))) / 2);
return Math.min(minDrops, findFloor(eggs - 1, minDrops));
}
for (let i=1; i<10; i++){
for (let j=1; j<10; j++){
let a = f(i,j);
let b = findFloor(i,j);
if (a != b){
console.log(`n,k: ${i},${j}; f: ${a}; findFloors: ${b}`);
}
}
}