390. 消除游戏 Elimination Game

390. 消除游戏 Elimination Game

题目描述

题目链接
给定一个从1 到 n 排序的整数列表。
首先,从左到右,从第一个数字开始,每隔一个数字进行删除,直到列表的末尾。
第二步,在剩下的数字中,从右到左,从倒数第一个数字开始,每隔一个数字进行删除,直到列表开头。
我们不断重复这两步,从左到右和从右到左交替进行,直到只剩下一个数字。
返回长度为 n 的列表中,最后剩下的数字。

示例:

输入:
n = 9,
1 2 3 4 5 6 7 8 9
2 4 6 8
2 6
6

输出:
6

解题思路

此题是约瑟夫问题的变体,可以总结递推公式求解。

下面通过举例来总结此问题的规律。当n=9时,子问题分解如下:

当前列表 删除方向
1 2 3 4 5 6 7 8 9 从左到右删除
2 4 6 8 将当前列表看成1 2 3 4,结果乘以2再返回
1 2 3 4 从右到左删除,结果返回
1 3 将当前列表看成2 4,结果减1再返回
2 4 将当前列表看成1 2,结果乘以2再返回
1 2 从左到右删除,结果返回
2 剩余1个数,结果返回

当n=10时,子问题分解如下:

当前列表 删除方向
1 2 3 4 5 6 7 8 9 10 从左到右删除
2 4 6 8 10 将当前列表看成1 2 3 4 5,结果乘以2再返回
1 2 3 4 5 从右到左删除,结果返回
2 4 将当前列表看成1 2,结果乘以2再返回
1 2 从左到右删除,结果返回
2 剩余一个数,结果返回

从上面可以看出,递归时需要判断的条件有两个。一个是删除方向,一个是列表的长度是否被2整除。

如果列表长度是奇数,并且是从左到右删除,例如是 1 2 3 4 5 6 7 8 9,那么结果和 1 2 3 4 5 6 7 8 相同。
如果列表长度是奇数,并且是从右到左删除,例如是 1 2 3 4 5 6 7 8 9,那么结果和 2 4 6 8 相同,也就是 1 2 3 4 乘以2。
如果列表长度是偶数,并且是从左到右删除,例如是 1 2 3 4 5 6 7 8,那么结果和 2 4 6 8 相同,也就是 1 2 3 4 的结果乘以2。
如果列表长度是偶数,并且是从右到左删除,例如是 1 2 3 4 5 6 7 8,那么结果是 1 3 5 7 ,也就是 2 4 6 8 的结果减1,也就是 1 2 3 4 的结果乘以2再减1。

递推公式如下(其中n代表列表长度,direc代表删除方向,0代表从左到右删除,1代表从右到左删除),并且f(1)=1:
f ( n , d i r e c ) = { 2 f ( n / 2 , 1 ) , d i r e c = 0 & & n % 2 = 0 f ( n 1 , 0 ) , d i r e c = 0 & & n % 2 0 2 f ( n / 2 , 0 ) 1 , d i r e c = 1 & & n % 2 = 0 2 f ( n / 2 , 0 ) , d i r e c = 1 & & n % 2 0 f(n, direc) = \left\{ \begin{aligned} 2*f(n/2, 1),direc=0\And\And n\%2=0 \\ f(n-1, 0),direc=0\And\And n\%2\not=0 \\ 2*f(n/2, 0)-1,direc=1\And\And n\%2=0 \\ 2*f(n/2, 0),direc=1\And\And n\%2\not=0 \\ \end{aligned} \right.

代码如下:

class Solution {
public:
    int lastRemainingWithDirec(int n, int direction) { // direction等于0代表从左到右,等于1代表从右到左
        if (n == 1) return 1;
        else if (direction == 0) {
            if (n % 2 == 0) return 2 * lastRemainingWithDirec(n / 2, 1);
            else return lastRemainingWithDirec(n - 1, 0);
        }
        else {
            if (n % 2 == 0) return 2 * lastRemainingWithDirec(n / 2, 0) - 1;
            else return 2 * lastRemainingWithDirec(n / 2, 0);
        }
    }
    int lastRemaining(int n) {
        return lastRemainingWithDirec(n, 0);
    }
};
发布了2 篇原创文章 · 获赞 6 · 访问量 171

猜你喜欢

转载自blog.csdn.net/lovepon/article/details/104121498