循环数字

时间:2013-09-07 01:50:25

标签: javascript josephus

所以这是给出的问题。

你在一个有100个椅子的房间里。椅子按顺序从1到100编号。

在某个时间点,#1椅子上的人将被要求离开。将跳过椅子#2中的人,并且将要求椅子#3中的人离开。这种跳过一个人并要求下一个人离开的模式会一直绕着圆圈走,直到有一个人离开,幸存者。

这就是我提出的答案。我相信这是正确的答案,我在纸上做了大约10次,每次都得到74。 这是一个棘手的问题还是什么?因为我不知道该怎么做。

这是jsfiddle http://jsfiddle.net/cQUaH/

var console = {
    log : function(s) {
        document.body.innerHTML += s + "<br>";
    }
};

var chairArr = [];
for (var i = 1; i <= 100; i++){
    chairArr.push(i);
}

var j = 2;
while(chairArr.length > 1) {
    console.log('removing ' + chairArr[j]);
    chairArr.splice(j, 1);
    j++;
    if(j >= chairArr.length) {
       console.log('--- Finished pass');
       console.log('--- Array state:');
       console.log(chairArr);
       j = (j == chairArr.length) ? 0 : 1;   
    } 
}
console.log('--- Final result: ' + chairArr); 
//result 74

4 个答案:

答案 0 :(得分:6)

如果索引发生微小变化,您就会遇到 Josephus问题。在传统的公式中,人1杀人2,3杀4等。要转换为该形式,杀掉人1,如你的问题所述,然后通过减去1给人2-100,给人1-99。

对约瑟夫斯问题的一个很好的处理,包括其在70-73 CE犹太人起义中的起源,在格雷厄姆,克努特和帕塔什尼克的具体数学,第2版,第1.3节。维基百科和Wolfram MathWorld都有关于这个问题的文章,维基百科甚至包括约瑟夫斯在犹太战争中的原始描述。

本书为解决方案提供了一个稍微复杂的递归,并提供了一种更简单的算法。如果人数为nn = 2^l + m l尽可能大,那么答案为2m+1。因此,自99 = 2^6 + 35起,解决方案为2*35 + 1 = 71。但是你需要反转重新编号,所以真正的答案是72

然而,就你的编程问题而言,为什么不把你作为基本操作删除圈子中的第一个人并将第二个人移到最后。所以,{{em> 1}}人,5,删除第一个获取[1,2,3,4,5]并将新的第一个元素移动到最终获得[2,3,4,5]

[3,4,5,2]

然后主循环变为:

var killAndRotate = function(array) { // say [1,2,3,4,5]
    var dead    = array.shift(),      // dead    = 1, array = [2,3,4,5]
        skipped = array.shift();      // skipped = 2, array = [3,4,5]
    array.push(skipped);              //              array = [3,4,5,2]
}

找到原始Josephus问题的简单方法是看到:

如果有while (chairArray.length > 1) { killAndRotate(chairArray); } alert(chairArray[0]); // or console.log, or return. // In turn, array is: // [1,2,3,4,5] // [3,4,5,2] // [5,2,4] // [4,2] // [2] and we alert, log, or return 2. 人,那么在第一次通过时,所有偶数人都会被杀死,所以第一个人还活着。

2^l

现在有1 2 3 4 5 6 7 8 X X X X 人。同样,第一个人幸存下来:

2^(l - 1)

重复这个过程;第一个人每次通过幸存者,最后一个幸存者也是如此。

现在,假设1 2 3 4 5 6 7 8 X X X X X X m个额外人员。在此处m < 2^ll = 3。杀死第一批m = 5人死亡。

m

现在,剩下1 2 3 4 5 6 7 8 9 10 11 12 13 X X X X X Y 人,而人2^l是排在第一位的人。所以他活了下来。

还应该指出,添加新索引变量和拼接可能会导致程序员错误。由于您只需要从前面移除并添加到后面,因此请使用数组的基本方法。

答案 1 :(得分:3)

你在这里描述的是Josephus问题,可以使用动态编程来解决:

function josephus(n, k) 
{ 
    if (n == 1) { 
        return 1; 
    } else { 
        return ((josephus(n-1, k) + k - 1) % n) + 1; 
    }
}

alert(josephus(100, 2));

来源:Wikipedia

n表示椅子数量,k表示每个第k个人离开。

这里的结果是73。

<强>更新

不幸的是,我没有正确阅读问题。上面的代码解决了一个稍微不同的问题;第二人被杀,而不是第一轮杀死第一个人。成为幸存者取决于细节:)

解决您的代码问题非常简单,首先是第一人而不是第一人。

var chairArr = [];

for (var i = 1; i <= 100; i++){
    chairArr.push(i);
}

var j = 0;
while (chairArr.length > 1) {
    chairArr.splice(j, 1);
    j = (j + 1) % n;
}

答案 2 :(得分:3)

在我看来答案是72.当你意识到不是删除数字而是可以跳过它们时,代码变得非常简短直接。

var chairArr = [];
for (var i = 1; i <= 100; i++)
    chairArr.push(i);

for (i = 1; i < chairArr.length-2; i = i + 2)
    chairArr.push(chairArr[i]);

console.log('--- Final result: ' + chairArr[i]);

答案 3 :(得分:0)

您不需要进行迭代即可找到结果,可以使用以下公式获取最终主席:

function findChair (input) {
  return (input - Math.pow(2, Math.floor(Math.log2(input)))) * 2 || (input === 1 ? 0 : input)
}

对于最初的约瑟夫斯问题(取而代之的是杀死偶数),可以简化公式:

function findChair (input) {
  return (input - Math.pow(2, Math.floor(Math.log2(input)))) * 2 + 1
}

关于原始问题的很酷的事情是,您可以使用二进制文件。例如:

100 = 1100100

取第一个“ 1”并将其放置在最后一个:

1001001 = 73