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. 项目中git分支管理策略

  2. bug生命周期&bug跟踪处理

    一.BUG BUG:软件的缺陷 1.BUG的定义:----与软件测试的目的对应 软件的BUG,狭义概念是指软件程序的漏洞或缺陷,广义概念除此之外还包括测试工程师或用户所发现和提出的软件可改进的细节.或 ...

  3. 第六周LINUX学习笔记

    DNS服务 DNS:Domain Name Service //协议     实现:BIND(Berkeley Internet Name Domain)     监听端口:        UDP:5 ...

  4. ReactNative之结合具体示例来看RN中的的Timing动画

    今天继续更新RN相关的博客.上篇博客详细的聊了RN中关于Flex布局的相关东西,具体请参见<ReactNative之参照具体示例来看RN中的FlexBox布局>.本篇博客继续更新RN的动画 ...

  5. mysql的学习笔记(七)

    1.自定义函数,函数可以返回任意类型的值,同样可接说这些类型的参数. CREATE FUNCTION function_name RETURNS {STRING|INTER|REAL|DECIMAL} ...

  6. 《前端之路》之二:数据类型转换 && 隐式转换 || 显式转换

    目录 02:数据类型转换 && 隐式转换 || 显式转换 02:数据类型转换 && 隐式转换 || 显式转换 在上一个章节中,我们介绍了 JavaScript 的基本的 ...

  7. Java中的基本类型转换,数据溢出原理

    java中的数据类型 java是一种强类型语言,在java中,数据类型主要有两大类,基本数据类型和引用数据类型,不同的数据类型有不同的数据存储方式和分配的内存大小. 基本数据类型中,各数据类型所表示的 ...

  8. GetTypes Unable to load one or more of the requested types

    重新生成项目,更新反射类的dll文件

  9. 微信小程序开发07-列表页面怎么做

    接上文:微信小程序开发06-一个业务页面的完成 github地址:https://github.com/yexiaochai/wxdemo 我们首页功能基本完成,我对比了下实际工作中的需求,完成度有7 ...

  10. SQL之case when then用法(用于分类统计)

    case具有两种格式.简单case函数和case搜索函数. --简单case函数 case sex when '1' then '男' when '2' then '女’ else '其他' end ...