2022.01.02 Leetcode 每日一题 消除游戏

本文介绍了一种交替从左右删除元素的数列操作,直到只剩下一个数字的算法。通过分析等差数列的性质,我们发现每轮删除后数列长度减半,公差翻倍。最终,通过模拟这一过程,给出了一种高效的解决方案。该算法适用于处理大规模数据,避免了超时问题。
摘要由CSDN通过智能技术生成

1、题目消除游戏

列表 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
提示:
1 <= n <= 10^9

2、分析

经过分析,我们可以发现

  1. 对于长度为n的数列,经过删除,其长度变为 ⌊ x / 2 ⌋ \lfloor {x/2} \rfloor x/2
  2. 每一轮删除之后,剩下的都是等差数列。而等差数列可以用 a 0 a_0 a0和公差来表示, a n a_n an可以通过 a 0 a_0 a0和公差以及队列长度表示。所以我们只需要表示出每轮之后, a 0 a_0 a0和公差及数列长度的变化即可。
  3. 对于从左往右的删除,原来的 a 0 a_0 a0一定会被删除,而新的 a 0 a_0 a0就等于旧的 a 0 a_0 a0+公差。对于从右向左的删除,如果长度为偶数个,那么 a 0 a_0 a0不会被删除,否则会被删除,新的值为旧的 a 0 a_0 a0 + 公差。

3、题解

class Solution {
public:
    int lastRemaining(int n) {
       //a0,公差,轮数初始化
       int begin = 1, step = 1,cnt = 1;
       while(n != 1)
       {
           if(cnt % 2) begin += step;
           else if(n % 2) begin += step;
           //公差每轮变大一倍
           step += step;
           //数列长度缩短一倍
           n >>= 1;
           //删除轮数+1
           cnt ++;
       }
       return begin;
    }
};

4、总结

  1. 对于等差数列可以用 a 0 a_0 a0、公差、长度来进行表示,而无需处理整个队列的所有元素。一开始进行模拟的时候超时了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值