Elimination Game

这道题目出于leetcode,题目虽然很简单但是很有趣,因为有趣才能称得上游戏吧!

0x00 题目介绍

简单介绍一下题目意思

给定一个数字N(N>0),一个列表存着1~N的数字。每次从左到右从第一个数字开始,然后隔开一个数字删除数字,一直删除到最后再从右向左删除,一直删除到只剩下一个数字。

Example:

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

0x01 解法

解法一 按部就班

  1. 思想:直接按照题目意思,模拟删除步骤
  2. 代码:
int lastRemaining(int n) {
int start = 1, step = 1;
while (n > 1) {
//模拟删除元素一直到最后元素
start += step + (n-2)/2 * 2*step;
//每删除一轮剩余元素为该轮元素的一半
n /= 2;
//每次到达最后一个元素反向并且步数扩大两倍
//因为每次都隔开删除一个元素,
//所以下一轮的步数都是上一次的两倍
step *= -2;
}
return start;
}

算法时间复杂度:O(logN),空间复杂度O(1);

代码思想简单,易懂,一般最开始想到的也是这种算法

解法二 来去递归(一)

  1. 思想

    模拟去回删除元素,去即为从左到右,回即为从右往左,用一个变量代表状态,

    每轮删除后剩余这轮元素的一半.递归退出条件为当剩余元素为

    我们设F(N) 为从{1~N}删除的剩余元素.

    1). 从左往右删除

    那么每次删除掉的元素为奇数项元素,剩下的元素里全部都是偶数元素,并且最终结果也在这些元素里面.

    那么此时我们将所有元素同时除以2,此时元素又变为{1N/2},此时问题就变为找出{1N/2}剩余元素*2

    即:F(N) = 2*F(N/2);

    (方向----> N为偶数8) 1 2 3 4 5 6 7 8

    剩余的元素在2{1,2,3,4}里面 即2F(8/2);

    (方向----> N为奇数9)

    1 2 3 4 5 6 7 8 9

    剩余元素为2{1,2,3,4}即 2F(9/2)

    2). 从右往左删除

    如果最后一个元素是偶数,如果我们从右往左删除,剩余元素全部为奇数,为了使得剩余元素全部为偶数

    (方便下一步运算,因为我们需要把N的问题分解为N/2的问题)那么我们将所有元素 加1,这样删除后

    剩余元素就全部变为偶数了,为了弥补加1,我们需要在获得的结果后减1;

    所以当从左往右的时候F(N) = F(N/2)-(1-N%2)=F(N/2)-1+N%2

    比如:当N=8 list = {1,2,3,4,5,6,7,8}

    (方向<---- N为偶数8)

    1 2 3 4 5 6 7 8

    答案在剩余元素{1,3,5,7}里面,如果我们写作2{1,2,3,4}答案明显不对,需要修正变为2{1,2,3,4}-1即2*F(8/2)-1;

    (方向<---- N为奇数9)

    1 2 3 4 5 6 7 8 9

    剩余元素为2{1,2,3,4}即 2F(9/2)

    如果我们使用2*F(4/2) 答案明显不对了,所以我们需要在此基础上需要加上一个offset 1 或者在开始的基础上加一

  2. 递归版本代码

int getNext(int n,bool direction){
if(n==1) return 1;
//判断方向 从左往右
if(direction) return 2*getNext(n/2,!direction);
// 从右往左 偶数需要减一
else return 2*(getNext(n/2,!direction))-1+n%2;
}
int lastRemaining1(int n) {
return getNext(n,true);
}

时间复杂度O(logN) 空间复杂度O(logN)

  1. 迭代版本代码
/*
direction:删除方向 true:从左往右 false:从右往左
ratio: 记录当前删除深度
offset: 偏移值(分析如上)
*/
int lastRemaining(int n) {
bool direction = true;
int ratio = 1;
int offset = 0;
while(n!=1){
if(!direction && n%2==0)
offset+=ratio;
ratio<<=1;
n/=2;
direction=!direction;
}
return ratio-offset;
}

时间复杂度O(logN) 空间复杂度O(1)

解法三 来去递归(二)

  1. 算法思想

    也是来往依次删除,把每次删除操作统一为一个方向.这样不需要每次判定方向如何,

    也不需要判定是否为偶数再去减掉偏移值.

    如何将删除方向统一为一个方向呢?

    注意:我们每次都是先从左往右删除

    例如:当N=8时

    方向(---->) 1 2 3 4 5 6 7 8

    剩余元素在:2*{1,2,3,4}里面, 接着删除,此时我们删除方向反向为右往左.

    如果我们将{1,2,3,4}反转,并用4+1-反转后的结果

    即:4+1 - {1,2,3,4} = {4,3,2,1} 此时我们从右往左删除{4,3,2,1}就转化为从左往右删除{1,2,3,4}

    方向就统一了起来.当然N为奇数的时候也是一样,读者可以手动模拟一下

  2. 代码

int lastRemaining(int n) {
if(n <= 1) { return 1; }
//每次需要删除元素减半
n >>= 1;
//将方向反转 且结果需要乘以2
return (1 + n - lastRemaining2(n)) << 1;
};

时间复杂度O(logN) 空间复杂度O(1)

短短三行代码就解决了问题,短小精悍!

0x02结论

有趣的题目千篇一律,精致的解法百里挑一!

Elimination Game题解的更多相关文章

  1. Codeforces Round #606 (Div. 2, based on Technocup 2020 Elimination Round 4) 题解

    Happy Birthday, Polycarp! Make Them Odd As Simple as One and Two Let's Play the Words? Two Fairs Bea ...

  2. Technocup 2020 Elimination Round 3题解

    传送门 \(A\) 曲明连sb模拟不会做,拖出去埋了算了 //quming #include<bits/stdc++.h> #define R register #define fi fi ...

  3. 题解-CSA Beta Round#1 Number Elimination

    Problem CSA-Beta Round#3 题意概要:给定 \(n\) 个数组成的序列,定义一次操作: 在当前序列中选择两个数,将其中较小的数从序列中删除(若两个数相同,则删除在序列中更靠前的) ...

  4. Codeforces Round #591 (Div. 2, based on Technocup 2020 Elimination Round 1) 题解

    A..B略 C 对当前的值排序,再二分答案,然后对于(i%x==0 && i%y==0)放入大的,再放其他的贪心解决即可. #include<iostream> #incl ...

  5. CF1445B Elimination 题解

    Content 一个比赛分两场进行,其中: 第一场的第一百名成绩为 \(a\),且第一场的前一百名在第二场中都至少得到了 \(b\) 分. 第二场的第一百名成绩为 \(c\),且第二场的前一百名在第一 ...

  6. hdu4975 A simple Gaussian elimination problem.(正确解法 最大流+删边判环)(Updated 2014-10-16)

    这题标程是错的,网上很多题解也是错的. http://acm.hdu.edu.cn/showproblem.php?pid=4975 2014 Multi-University Training Co ...

  7. 高斯消元法(Gauss Elimination)【超详解&模板】

    高斯消元法,是线性代数中的一个算法,可用来求解线性方程组,并可以求出矩阵的秩,以及求出可逆方阵的逆矩阵.高斯消元法的原理是:若用初等行变换将增广矩阵 化为 ,则AX = B与CX = D是同解方程组. ...

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

    突然很想刷刷题,LeetCode是一个不错的选择,忽略了输入输出,更好的突出了算法,省去了不少时间. dalao们发现了任何错误,或是代码无法通过,或是有更好的解法,或是有任何疑问和建议的话,可以在对 ...

  9. Codeforces Round #596 (Div. 2, based on Technocup 2020 Elimination Round 2)

    A - Forgetting Things 题意:给 \(a,b\) 两个数字的开头数字(1~9),求使得等式 \(a=b-1\) 成立的一组 \(a,b\) ,无解输出-1. 题解:很显然只有 \( ...

随机推荐

  1. HDP 2.6 requires libtirpc-devel

    HDP 2.6 requires libtirpc-devel 个问题,截止 Mustafa Kemal MAYUK 2017年06月30日 06:30 hadoopPowerSystems Hell ...

  2. Storm入门(十一)Twitter Storm源代码分析之CoordinatedBolt

    作者: xumingming | 可以转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: http://xumingming.sinaapp.com/811/twitter-stor ...

  3. 跨域405(Method Not Allowed)问题

    zepot post没有问题,用plupload上传出现了这个错误,options过不去.显示Response for preflight has invalid http status code 4 ...

  4. Hadoop系列007-HDFS客户端操作

    title: Hadoop系列007-HDFS客户端操作 date: 2018-12-6 15:52:55 updated: 2018-12-6 15:52:55 categories: Hadoop ...

  5. Java笔试题库之选题题篇【71-140题】

    71下面哪几个函数是public void method(){̷}的重载函数?() A.public void method( int m){̷} B.public int method(){̷} C ...

  6. [intellij IDEA]导入eclipse项目

    1.因为最近eclipse在更新代码时经常卡死,就想将eclipse的项目迁移到idea.特意写下自己的经验,给迁移时遇到困难的朋友一些帮助 File -> new ->project f ...

  7. 获得当前EIP的值

    VS2017 内联汇编 __asm { call NEXT NEXT: pop eax }

  8. ES6躬行记(21)——类的继承

    ES6的继承依然是基于原型的继承,但语法更为简洁清晰.通过一个extends关键字,就能描述两个类之间的继承关系(如下代码所示),在此关键字之前的Man是子类(即派生类),而在其之后的People是父 ...

  9. kubernetes系列10—存储卷详解

    本文收录在容器技术学习系列文章总目录 1.认识存储卷 1.1 背景 默认情况下容器中的磁盘文件是非持久化的,容器中的磁盘的生命周期是短暂的,这就带来了一系列的问题:第一,当一个容器损坏之后,kubel ...

  10. java类的继承(基础)

    ---恢复内容开始--- 这篇随笔和大家讲讲java中类的继承是什么?希望对你们有所帮助. 目录 一.java继承是什么? 二.为什么使用java继承 三.java继承的实现 1.1  java继承的 ...