leetcode 390. Elimination Game

来源:互联网 发布:机顶盒有必要买吗 知乎 编辑:程序博客网 时间:2024/05/21 14:47

There is a list of sorted integers from 1 to n. Starting from left to right, remove the first number and every other number afterward until you reach the end of the list.

Repeat the previous step again, but this time from right to left, remove the right most number and every other number from the remaining numbers.

We keep repeating the steps again, alternating left to right and right to left, until a single number remains.

Find the last number that remains starting with a list of length n.

Example:

Input:n = 9,1 2 3 4 5 6 7 8 92 4 6 82 66Output:6

我本来想按照它的步骤一步步算的,结果Memory Limit Exceeded了,无奈,只能看众大神的解法。这个跟约瑟夫环问题有点相像,但是解法不太一样。

递归解法:

    public int lastRemaining(int n) {        return leftToRight(n);    }          // eliminate [1...n] first from left to right, then alternate    private int leftToRight(int n) {        if (n == 1) return 1;        // scan from left to right is simple, the length of array doesn't matter        // [1, 2, 3, 4] -> 2 * [1, 2]        // [1, 2, 3, 4, 5] -> 2 * [1, 2]        return 2 * rightToLeft(n / 2);    }        // eliminate [1...n] first from right to left, then alternate    private int rightToLeft(int n) {        if (n == 1) return 1;        // if the length of array is even, we will get only odd number        // [1, 2, 3, 4] -> [1, 3] = 2 * [1, 2] - 1        if (n % 2 == 0) return 2 * leftToRight(n / 2) - 1;        // else if the length of array is odd, we will get only even number        // [1, 2, 3, 4, 5] -> [2, 4] = 2 * [1, 2]        else return 2 * leftToRight(n / 2);    }
迭代解法:

思路是在每个回合,记录当前的head。当只剩下一个数字时,这个数字就是head。
那什么时候head会被更新呢?
1.  当从左到右删元素时,head会被更新。
2.  当从右到左删元素时,且元素的个数是奇数时,head会被更新。
     如 2 4 6 8 10, 元素个数为奇数,我们要删除 10, 6 , 2,head会被更新为4 
     如 2 4 6 8 10 12, 元素个数为偶数,我们要删除 12, 8, 4,head保持不变,为2

    public int lastRemaining(int n) {        boolean left = true;        int remaining = n;        int step = 1;        int head = 1;        while (remaining > 1) {            if (left || remaining % 2 ==1) {                head = head + step;            }            remaining = remaining / 2;            step = step * 2;            left = !left;        }        return head;    }

例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

  1. 开始时 head = 1, left = true, step = 1 (每个回合step乘以2), remaining = n(24)

  2. 从左到右删元素,我们只需要把head移到下一个位置:(head = head + step)
    第一回合后,变化:
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24- > 2 4 6 8 10 12 14 16 18 20 22 24
    head = 2, left = false, step = 1 * 2 = 2, remaining = remaining / 2 = 12

  3. 下一回合,从右到左删元素。remaining % 2 = 12 % 2 = 0,我们不需要改变head。
    第二回合后,变化:
    2 4 6 8 10 12 14 16 18 20 22 24 - > 2 6 10 14 18 22
    head = 2, left = true, step = 2 * 2 = 4, remaining = remaining / 2 = 6

  4. 第三回合, 从左到右删元素,我们把head移到下一个位置:
    第三回合后,变化:
    2 6 10 14 18 22 - > 6 14 22
    head = 6, left = false, step = 4 * 2 = 8, remaining = remaining / 2 = 3

  5. 第四回合,从右到左删元素。remaining % 2 = 3 % 2 = 1,我们需要把head移到下一个位置。
    第四回合后,变化:
    6 14 22 - > 14
    head = 14, left = true, step = 8 * 2 = 16, remaining = remaining / 2 = 1

  6. while循环停止,返回 head=14


原创粉丝点击