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 9
2 4 6 8
2 6
6 Output:
6

这道题是 LeetCode 第二次编程比赛的题,然而博主并没有做出来,博主用的方法是那种最笨的方法,用一个数组把n个数组都存起来,然后根据循环的奇偶来决定是从左还是从右删除,结果不幸超时 TLE 了。后来通过想大神请教和上网搜索,发现这道题用递归来做很简单,用一个 bool 型变量 left2right,为 true 表示从左往右,为 false 表示从右往左遍历。当n为1时,不论从左往右还是从右往左都返回1。如果n大于1,且是从左往右的话,返回2倍的对 n/2 的从右往左的遍历;如果是从右往左的话,稍稍麻烦一些,肯定还是要对 n/2 调用递归函数的,但是要分奇偶情况,如果n为奇数,返回2倍的对 n/2 的从左往右的遍历的值;如果n为偶数,2倍的对 n/2 的从左往右的遍历的值,再减去1。具体这样的原因,博主还在研究中,也不是太清楚:

解法一:

class Solution {
public:
int lastRemaining(int n) {
return help(n, true);
}
int help(int n, bool left2right) {
if (n == ) return ;
if (left2right) {
return * help(n / , false);
} else {
return * help(n / , true) - + n % ;
}
}
};

下面这种方法相当的叼,一行就搞定了简直丧心病狂啊。第一次从左往右删除的时候,奇数都被删掉了,剩下的都是偶数。如果对所有数都除以2,那么得到一个1到 n/2 的新数列。下一次从右往左删出,那么返回的结果应该是调用递归的结果 lastRemaining(n / 2) 在数组1到 n/2 之间的镜像。何为镜像,比如 1, 2, 3, 4 这个数字,2的镜像就是3, 1的镜像是4,参见代码如下:

解法二:

class Solution {
public:
int lastRemaining(int n) {
return n == ? : * ( + n / - lastRemaining(n / ));
}
};

下面这种迭代的解法是博主请教另一位大神的方法,个人感觉也非常叼,膜拜大神中,先来看两个简单的例子:

n = 8
1 2 3 4 5 6 7 8
   2    4    6   8
   2          6
               6
      
n = 7      
1 2 3 4 5 6 7
   2    4    6
         4

如果仔细观察,可以发现从左往右删的时候,每次都是删掉第一个数字,而从右往左删的时候,则有可能删掉第一个或者第二个数字,而且每删一次,数字之间的距离会变为之前的两倍。这里要做的是每次记录当前数组的第一个数字,而且再通过观察可以看出,从右往左删时,如果剩下的数字个数是偶数个时,删掉的是第二个数字;如果是奇数个的时候,删掉的是第一个数字。总结出了上述规律,就可以写出代码如下:

解法三:

class Solution {
public:
int lastRemaining(int n) {
int step = , res = ;
while (step * <= n) {
res += step;
step *= ;
if (step * > n) break;
if ((n / step) % == ) res += step;
step *= ;
}
return res;
}
};

再来看一种论坛上的高分解法,其实这种解法的本质跟上面那种解法一样的,这里多使用了两个变量,一个是布尔型变量 left2right,表示当前的方向,为 true 表示是从左往右删;另一个是整型变量 remain,表示当前还剩下的数字个数。当 remain 大于1的时候进行循环,res 表示的是当前剩下的左数第一个数字。根据之前的分析,当从左往右删除的时候,左边第一个数字一定会被删掉;而从右往左删时,如果剩下的数字个数是偶数个时,删掉的是第二个数字;如果是奇数个的时候,删掉的是第一个数字。这样只要判断 left2right 为 true,或者 remain 是奇数的时候,res 要加上 step,也就是当前数字之间的间隔数,每删除一次,step 都要自乘以2,同时 remain 要除以2,left2right 也要变成其相反的状态,参见代码如下:

解法四:

class Solution {
public:
int lastRemaining(int n) {
bool left2right = true;
int res = , step = , remain = n;
while (remain > ) {
if (left2right || remain % == ) res += step;
remain /= ;
step *= ;
left2right = !left2right;
}
return res;
}
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/390

类似题目:

https://leetcode.com/problems/elimination-game/

https://leetcode.com/problems/elimination-game/discuss/87128/C-1-line-solution-with-explanation

https://leetcode.com/problems/elimination-game/discuss/87121/O(logN)-solution.-clear-break-down

https://leetcode.com/problems/elimination-game/discuss/87120/one-line-java-solution-based-on-Josephus-Problem

https://leetcode.com/problems/elimination-game/discuss/87119/JAVA%3A-Easiest-solution-O(logN)-with-explanation

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] 390. Elimination Game 淘汰游戏的更多相关文章

  1. 390 Elimination Game 淘汰游戏

    详见:https://leetcode.com/problems/elimination-game/description/ C++: 方法一: class Solution { public: in ...

  2. [LeetCode] Elimination Game 淘汰游戏

    There is a list of sorted integers from 1 to n. Starting from left to right, remove the first number ...

  3. [leetcode] 390 Elimination Game

    很开心,自己想出来的一道题 There is a list of sorted integers from 1 to n. Starting from left to right, remove th ...

  4. 【LeetCode】390. Elimination Game 解题报告(Python)

    [LeetCode]390. Elimination Game 解题报告(Python) 标签: LeetCode 题目地址:https://leetcode.com/problems/elimina ...

  5. Java实现 LeetCode 390 消除游戏

    390. 消除游戏 给定一个从1 到 n 排序的整数列表. 首先,从左到右,从第一个数字开始,每隔一个数字进行删除,直到列表的末尾. 第二步,在剩下的数字中,从右到左,从倒数第一个数字开始,每隔一个数 ...

  6. leetcode 390. 消除游戏

    {20-01-29 19:22} class Solution { public int lastRemaining(int n) { return help(n); } public static ...

  7. 【leetcode】390. Elimination Game

    题目如下: 解题思路:对于这种数字类型的题目,数字一般都会有内在的规律.不管怎么操作了多少次,本题的数组一直是一个等差数列.从[1 2 3 4 5 6 7 8 9] -> [2 4 6 8] - ...

  8. [LeetCode] Burst Balloons 打气球游戏

    Given n balloons, indexed from 0 to n-1. Each balloon is painted with a number on it represented by ...

  9. [LeetCode] Game of Life 生命游戏

    According to the Wikipedia's article: "The Game of Life, also known simply as Life, is a cellul ...

随机推荐

  1. 明解C语言 入门篇 第十一章答案

    练习11-1 /* 用指针实现的字符串的改写 */ #include <stdio.h> int main(void) { "; printf("p = \" ...

  2. Visual Studio 语法高亮插件推荐

    编辑器 GItHub:https://github.com/Art-Stea1th/Enhanced-Syntax-Highlighting Visual Studio Marketplace:htt ...

  3. Mybatis中的Mapper.xml映射文件sql查询接收多个参数

    ​ 我们都知道,在Mybatis中的Mapper.xml映射文件可以定制动态SQL,在dao层定义的接口中定义的参数传到xml文件中之后,在查询之前mybatis会对其进行动态解析,通常使用#{}接收 ...

  4. 第五篇 openvslam建图与优化模块梳理

    建图模块 mapping_module在初始化系统的时候进行实例化,在构建实例的时候会实例化local_map_cleaner和local_bundle_adjuster.系统启动的时候会在另外一个线 ...

  5. 基于直接缓冲区和非直接缓冲区的javaIO文件操作

    基本概念: 1. 非直接缓冲区:  指的是通过jvm来缓存数据的,应用程序要读取本地数据要经历从本地磁盘到物理内存,然后copy到jvm中,然后再通过流的方式读取到应用程序中,写的操作正好与之相反. ...

  6. Visual Studio2017使用EF添加Mysql

    为了能够在Visual Studio 中集成Mysql, 首先需要安装MySql的连接工具 与 MySql的VisualStudio插件. MySQL Connector Net 6.8.8 (目前最 ...

  7. python 手机app数据爬取

    目录 一:爬取主要流程简述 二:抓包工具Charles 1.Charles的使用 2.安装 (1)安装链接 (2)须知 (3)安装后 3.证书配置 (1)证书配置说明 (2)windows系统安装证书 ...

  8. CA of sharepoint2016

    总体来说,CA界面变动不大

  9. python3类和实例

    面向对象最重要的概念就是类(Class)和实例(Instance),必须牢记类是抽象的模板,比如Student类,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可 ...

  10. libtool编译

    1.充分利用共享库的能力.libtool 是一个通用库支持脚本 2.我们可以认为libtool是gcc的一个抽象,也就是说,它包装了gcc或者其他的任何编译器,用户无需知道细节,只要告诉libtool ...