Looping over numbers

筅森魡賤 提交于 2019-12-03 11:30:22

With a minor change in indices, you have the Josephus problem. In the traditional formulation, person 1 kills person 2, 3 kills 4, etc. To convert to that form, kill off person 1, as your problem states, and then renumber people 2-100 by subtracting 1, giving people 1-99.

A good treatment of the Josephus problem, including an account of its origin in the Jewish Revolt of 70-73 CE, is in Concrete Mathematics, 2nd edition, by Graham, Knuth, and Patashnik, Section 1.3. Both Wikipedia and Wolfram MathWorld have articles on the problem, Wikipedia even includes the original description by Josephus in The Jewish War.

The book gives a mildly complicated recursion for the solution, and a simpler algorithm. If the number of people is n, and n = 2^l + m where l is as large as possible, then the answer is 2m+1. So, since 99 = 2^6 + 35, the solution is 2*35 + 1 = 71. But you need to reverse the renumbering, so the real answer is 72.

As far as your programming problem, however, why don't you take as your basic operation Remove the first person in the circle and move the second person to the end. So, with 5 people, [1,2,3,4,5], you remove the first getting [2,3,4,5]and moving the new first element to the end getting [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]
}

And then the main loop becomes:

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.

Added

The easy way to find that result for the original Josephus problem is to see that:

If there are 2^l people, then in the first pass all the even-numbered people are killed, so the first person remains alive.

1 2 3 4 5 6 7 8

  X   X   X   X

Now there are 2^(l - 1) people. Again, the first person survives:

1 2 3 4 5 6 7 8

  X   X   X   X

    X       X

Repeat the process; the first person survives each pass, and so is the last survivor.

Now, suppose there are m extra people with m < 2^l. Here, l = 3 and m = 5. Kill the first m people to die.

1 2 3 4 5 6 7 8 9 10 11 12 13

  X   X   X   X    X  Y

Now, there are 2^l people left, and person 2 m + 1 = 11 is the first in line. So he survives.

One should also point out that adding a new index variable and splicing can lead to programmer error. Since you only need to remove from the front and add to the back, use the basic methods of arrays.

It seems to me the answer is 72. When you realize that rather than removing numbers you can skip them, the code becomes very short and straight-forward.

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]);

What have you described here is the Josephus problem, and can be solved using dynamic programming:

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

alert(josephus(100, 2));

Source: Wikipedia

The n denotes the number of chairs and k indicates every kth person leaving.

The result here is 73.

Update

Unfortunately, I didn't read the problem properly. The above code solves a slightly different problem; instead of killing off the first person in round one, the second person is killed instead. Being a survivor hinges on details :)

Solving your code problem is rather simple, start with the first person instead of the third in the first round.

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;
}

You don't need an iteration to find the result, there is a formula that can be use to obtain the final chair:

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

And for the original Josephus problem, which you kill the even numbers instead, the formula can be simplified:

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

The cool thing about the original problem, is that you can work with binary. For example:

100 = 1100100

Take the first '1' and place it to the last:

1001001 = 73

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!