11

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
Óscar López
  • 232,561
  • 37
  • 312
  • 386
user2677350
  • 338
  • 2
  • 13
  • What does the teacher say the answer should be? And why do you remove the person from chair #3 first when the question says #1 should go first? – nnnnnn Sep 07 '13 at 01:53
  • 1
    Why does `j` start at 2? – Matt Greer Sep 07 '13 at 01:55
  • This is the response I received. It looks solid but unfortunately you are just barely off the mark. Take another look and see if you see the mistake. – user2677350 Sep 07 '13 at 01:55
  • 1
    You state " the person in chair #1 will be asked to leave". The first time through you are not removing #1 so you need to adjust the variable j to zero. –  Sep 07 '13 at 01:55
  • That's where I'm confused, do I get rid of the 1st chair on the first pass, cause if so the ending result would be 72. I just wanted some extra eyes on this question to see where I'm going wrong, I think it's a trick question. – user2677350 Sep 07 '13 at 01:58
  • 3
    The question as you've stated it says that the person in chair #1 will leave first, but you started with #3. Why do you think it is a trick question? – nnnnnn Sep 07 '13 at 01:59
  • I guess it was the way he wrote it, that's why I got confused. I assumed since it said at some point chair 1 will be ask to leave, thats why I skipped it the first go around. – user2677350 Sep 07 '13 at 02:02
  • I think "at some point" merely points to the start of the operation where start by removing the first person.. – user1600124 Sep 07 '13 at 02:03
  • Btw, use the modulo operator for wrapping j – Ja͢ck Sep 07 '13 at 02:04
  • I just misunderstood the question to begin with, thanks guys for looking it over. – user2677350 Sep 07 '13 at 02:05
  • "At some point" this will happen, then this will happen, then that will happen. Read it that way. Don't read it "At this point this will happen. Oh, by the way, these other independent things happen (remove 3, 5,...)." – BLaZuRE Sep 07 '13 at 02:06
  • In your jfiddle i see 1 being removed in the second group. I think this is the error! I get 72 . If you think its a trick question post the exact question as it reads. Im not sure why i need to explain why to remove 1... the question states to do such... thus when coming back around the second time... 100 would be skip and then the next value would be 2 – tyler Sep 07 '13 at 01:58
  • @BLaZuRE why would i need to explain why i deleted 1 first its in the question....silly – tyler Sep 07 '13 at 02:08
  • @tman Because you deleted your answer, I need to retype this here: Explain how you get 72. It may not be as obvious to the OP or people who come by this question later, as it is to you. The OP wants to know **how** to achieve the answer, not **what** is the answer. As the OP has already stated, s/he didn't know that 1 should have been removed the 1st time around. – BLaZuRE Sep 07 '13 at 02:11
  • So far from what answers have been posted, I've got 73 and 72 which is the right answer? – user2677350 Sep 07 '13 at 02:38

4 Answers4

6

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.

Eric Jablow
  • 7,874
  • 2
  • 22
  • 29
  • "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." Math is so beautiful! – Joseph Myers Sep 07 '13 at 05:01
4

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]);
dcaswell
  • 3,137
  • 2
  • 26
  • 25
  • 1
    There is genius behind this answer that I don't think anyone noticed. What this answer is doing is adding the survivors to the end of the array. But despite that, very quickly the array index will catch up with the last survivor. This solution is beautiful, even to the point that your indexing lines up the post-loop value of `i` perfectly so that the lone survivor is in `chainArr[i]`. – Joseph Myers Sep 07 '13 at 05:00
3

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;
}
Ja͢ck
  • 170,779
  • 38
  • 263
  • 309
  • I don't understand why it's 73 and not 72. I read the wiki article and don't get it. When I do it on paper and get rid of 1,3,5 and so on I get 72. Please explain to me why this is the answer. – user2677350 Sep 07 '13 at 02:29
  • did u mean recursion by any chance? – Itay Moav -Malimovka Sep 07 '13 at 02:31
  • 1
    The Josephus problem removes even numbers, not odd numbers. – DiMono Sep 07 '13 at 02:32
  • @user2677350 I've got to run now, but I'll come back to explain :) it probably has to do with the first being skipped initially. – Ja͢ck Sep 07 '13 at 02:37
  • @ItayMoav-Malimovka Dynamic programming and recursion are not mutually exclusive, I hope you realize that :) – Ja͢ck Sep 07 '13 at 02:37
  • @DiMono What makes you think so? – Ja͢ck Sep 07 '13 at 02:39
  • @Jack the fact that I'm familiar with the Josephus problem. Person 1 kills person 2, person 3 kills person 4, etc., so you're always removing the even-numbered remaining people. The puzzle in the original post is to remove the odd-numbered remaining people. – DiMono Sep 07 '13 at 02:45
  • @user2677350 Right, so it's almost Josephus but not quite; I've fixed your code in my update. – Ja͢ck Sep 07 '13 at 04:09
  • @DiMono Okay, I see what you mean now, though I don't remember it with multiple people killing each other, rather a single executioner :) – Ja͢ck Sep 07 '13 at 04:09
  • @Jack , thank you for simplifying the code , I definitely learned a lot from asking this question. – user2677350 Sep 07 '13 at 04:23
0

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

rafaelkendy
  • 69
  • 10