390. 消除游戏
-
题目
列表 arr 由在范围 [1, n] 中的所有整数组成,并按严格递增排序。请你对 arr 应用下述算法:
从左到右,删除第一个数字,然后每隔一个数字删除一个,直到到达列表末尾。
重复上面的步骤,但这次是从右到左。也就是,删除最右侧的数字,然后剩下的数字每隔一个删除一个。
不断重复这两步,从左到右和从右到左交替进行,直到只剩下一个数字。
给你整数 n ,返回 arr 最后剩下的数字。
示例 1:
输入:n = 9
输出:6
解释:
arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
arr = [2, 4, 6, 8]
arr = [2, 6]
arr = [6]
示例 2:
输入:n = 1 输出:1
-
难度:中等
-
分类:多看
-
题解
这题官方给的题解非常明白了,我在下面根据官方题解进行复述再做些补充。
k 表 示 第 k 次 遍 历 删 除 。 k 初 始 值 为 0 , 不 难 明 白 , k 为 偶 数 从 左 到 右 删 除 , k 为 奇 数 从 右 到 左 。 a 1 k 表 示 第 k 次 删 除 的 第 一 个 数 的 值 在 官 方 题 解 当 中 考 虑 了 a n k 即 第 k 次 删 除 最 后 一 个 数 的 值 , 但 是 在 代 码 实 现 中 , 我 们 只 需 要 考 虑 第 一 个 值 的 变 化 k表示第k次遍历删除。k初始值为0,不难明白,k为偶数从左到右删除,k为奇数从右到左。\\ a_1^k表示第k次删除的第一个数的值\\ 在官方题解当中考虑了a_n^k即第k次删除最后一个数的值,但是在代码实现中,我们只需要考虑第一个值的变化\\ k表示第k次遍历删除。k初始值为0,不难明白,k为偶数从左到右删除,k为奇数从右到左。a1k表示第k次删除的第一个数的值在官方题解当中考虑了ank即第k次删除最后一个数的值,但是在代码实现中,我们只需要考虑第一个值的变化- 当k为偶数时,从左到右
- cnt为奇数,则前后两个数都要被删除,则第一个数的后移step
- cnt为偶数,则首元素会被删除,末端元素不被删除
- 当k为奇数时,从右到左
- cnt为奇数,则前后两个数都要被删除
- cnt为偶数,则首端元素被删除
那么我们将首端元素看作指针,移动这个元素的index,一直到cnt只有1,那么这个index就是最终的数就行。
- 当k为偶数时,从左到右
-
代码如下:
public int lastRemaining(int n) { int a1=1; int k=0; int cnt=n; int step=2; while(cnt>1){ if(k%2==0){ a1=a1+step; } else{ a1=(cnt%2==0)?a1:a1+step; } cnt=cnt>>1; step=step<<1; k++; } return a1; }
时间复杂度:o(logn)
空间复杂度:o(1)
小思考
这里我们处理的数组是[1,n]的n为长度的连续绝对递增的数组,那么我们处理任意数组应该怎么办呢?
那么答案也是非常简单,[1,n]的n为长度的连续绝对递增可以看作数组下标进行映射一下到[0,n-1],然后我们通过上面的代码对数组下表进行操作,最后得到的index,这个index-1对应的数,则是我们需要找到的数。其实就是简单映射关系。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/map-sum-pairs
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。