Question

So this is the question that is given.

You are in a room with a circle of 100 chairs. The chairs are numbered sequentially from 1 to 100.

At some point in time, the person in chair #1 will be asked to leave. The person in chair #2 will be skipped, and the person in chair #3 will be asked to leave. This pattern of skipping one person and asking the next to leave will keep going around the circle until there is one person left, the survivor.

And this is the answer I came up with. I believe this is the right answer, I've done it on paper about 10 times as well and came up with 74 every time. Is this a trick question or something? Because I'm not sure what to do from here.

Here is the 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
Was it helpful?

Solution

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.

OTHER TIPS

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

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top