Egg Dropping Puzzle - 需要建议

时间:2018-02-13 09:34:15

标签: algorithm puzzle

问题陈述

掉蛋指的是一类问题,在这些问题中,在不超过(低)数量的某些失效状态的情况下找到正确的响应非常重要。在一个玩具的例子中,有一个地板塔和一个理想蛋的蛋滴管。理想蛋的物理特性是,如果它从地板或以上掉落,它将会破碎,如果从地板或下面掉落,它将不会受到任何损害。问题是要找到一种策略,使蛋滴管能够尽可能少地确定蛋底。此问题在现实世界中有许多应用程序,例如避免调用慢速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));
})();

我已经测试了一些测试用例,但有人可以建议,这适用于所有场景吗?

2 个答案:

答案 0 :(得分:1)

不,这并不总能产生正确的结果。您已使用此公式:

enter image description here

但是,如果鸡蛋的数量是两个,那么该公式只能提供有意义的结果。注意鸡蛋的数量是如何出现的,只有楼层的数量( 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)

我相信已知的solutionO(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}`);
    }
  }
}