LeetCode-390. 消除游戏

2022年1月2日

题目消除游戏

思考

心情:  

明天计划:不用怼每日一题了,来点简单的吧

-------------------------------------------------------------------------------------------------------------------------------------

> 来自小助理的碎碎念

能力 > 动机,更容易产生正向情绪:我真牛!我觉得自己又可以了!*

能力 < 动机,会容易产生负面情绪:我是个废物!我就是颗卷心菜!*

感受正向情绪,是「习惯」的养分,如果你在挑战一件很难的事情的话,试着放低对自己的要求吧!
比如说,每天只做 1 道题,甚至每天看懂并复制 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

 

 

我的代码(屎山):

它是一个可以勉强跑起来的代码,直接模拟题目运行流程。但但是如果测试测试数据较大(即n比较大时),它就会有问题……时间复杂度是O(n^2),空间复杂度是O(n)。所以它是不合格的。(这代码看着像个没打好基础的人写的……还是看下面代佬写的吧)

复制代码
class Solution {
    public int lastRemaining(int n) {
        Object last = 1;
        List list  = new ArrayList();
        for(int i=1; i<n+1; i++){list.add(i);}
        if(1 == list.size()){
         return n;
        }
        while(list.size()!=1){
            for(int i=0; i<list.size();i++){
                if(list.size()==1){last = list.get(0);return (int)last;}
                list.remove(i);
            }
            for(int i=list.size()-1; i>=0; i--){
                if(list.size()==1){last = list.get(0);return (int)last;}
                list.remove(i--);
            }
            if(list.size()==1){last = list.get(0);return (int)last;}
        }
        return (int)last;
    }
}
复制代码

 

代佬的代码(金光闪闪):

一个表达式搞定==。

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

 

分析一下。主要是需要找到其中的规律。它这里找到规律之后分析出数学公式,直接带入即可算出(数学真的太重要了)。假设从f[i]开始从左往右间隔删除数字,将会得到一个长度为1/2 的f' 。然后f' 继续从右往左遍历。这两次从左往右、从右往左的删除过程,在列表f 看来是对称的。他们分别删除之后,剩下的值也会有对称性。举个例子:

a[]: 1 2 3 4 5 6
b[]: 6 5 4 3 2 1

上面两个列表,a[i]+b[i] = 7 = n+1,n即列表的长度。就算这两个列表经过了从左往右的一轮删除,剩下的值也还是符合a[i]  + b[i] = n+1 这个公式。所以在[1,i]这个列表中,可以得到公式:f[i]+f[i]=i+1。

当从右往左时,就比较特殊,需要对已经删过一次的列表做重新编号,让它继续保持连续序列的特性。然后再执行从右往左间隔删除。得到f'[i/2],然后将但编号映射回重新编号之前的值(这里有点没看明白),得到第二个公式:f[i]=f[2i]2

然后合并f[i]得到:f[i]=2(2i+1f[2i])。在代码中的实现就是递归调用lastRemaining方法。

 

具体的题解这里:说的更详细一些:https://leetcode-cn.com/problems/elimination-game/solution/gong-shui-san-xie-yue-se-fu-huan-yun-yon-x60m/#comment

 

posted @   我永远喜欢石原里美  阅读(82)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示