美文网首页
last one to survive 2022-01-03(未

last one to survive 2022-01-03(未

作者: 9_SooHyun | 来源:发表于2022-01-03 23:06 被阅读0次

本文来自于对leetcode #### 390. 消除游戏的扩展与思考

last one to survive 最后一人存活问题

关于最后一人存活问题,可以抽象成:
给定一个数组,每次按照一定规则去除数组中的若干元素,直到剩下最后一个元素,返回这个元素

根据去除元素的规则的不同,可以衍生出不同的存活玩法。如果你是数组所有元素中的一个,你如何保证自己最后活下来呢?

下面将通过几个玩法,学习如何将实际问题抽象成数学问题,学习问题的抽象

玩法1:每次从左到右kill奇数位置上的人,直到剩下最后一个人

这个玩法下,每一轮都只有偶数位置上的人存活。如:

[1,2,3,4,5,6,7]
->[2,4,6]
->[4] return 4

上面的例子可以给出感性的认识,

  • a.每一轮过后,剩下的元素个数 = 原元素个数 // 2
  • b.剩下的元素个数的位置下标 = 原下标 / 2

活下来的人在之前的任何一轮中都处在偶数位置,那么由b可以知道,活下来的人的编号必然是2^N, 且2^(N+1) > 初始元素个数
例子中N=2

玩法2:先从左到右kill奇数位置上的人,然后从左到右kill偶数位置上的人,不断循环,直到剩下最后一个人

例如:

[1,2,3,4,5,6,7,8,9] // 左到右删奇数位
->[2,4,6,8] // 左到右删偶数位
->[2,6] // 左到右删奇数位
->[6] return 6

这种玩法下,由于删除规则在有规律的变化,因此不像玩法1那样直观

但我们可以将问题进一步抽象:

无论我们删除奇数位置还是删除偶数位置,剩下的 1/2 数组都必然是一个等差数列,只是首项和公差在不断变化。而我们要求的,就是长度为1的等差数列的首项

在数学上,对于等差数列,确定了首项和公差,就确定了一切;换句话说,确定了首项和第二项,就确定了一切

在这个问题中,删除导致的首项和公差的变化是有迹可循的,是跟随每轮的删除变化的:

  • 左到右删奇数位,删除前的次项变成新首项,公差翻倍
  • 左到右删偶数位,首项不变,公差翻倍

于是,我们顺理成章地写出代码:

class Solution:
    def lastRemaining(self, n: int) -> int:
        # 每次总要删除一半或者一半+1的数,即总会剩下n//2个数
        # 当前长度psuedo_len
        psuedo_len = n
        # 当前所在的删除轮数
        round = 0
        # 首项
        first = 1
        # 次项
        second  = 2
        # 公差
        delta = 1
        while psuedo_len != 1:
            round += 1
            # 奇数轮删除(从左向右删奇数位,原次项变成删除后的首项)
            if round % 2 == 1:
                first = second
            # 偶数轮删除(左到右删偶数位,首项不变)
            else:
                  pass
            # 公差翻倍
            delta = 2*delta
            second = first + delta
            psuedo_len = psuedo_len // 2
        return first


玩法3:先从左到右kill奇数位置上的人,然后从右到左反向kill奇数位置上的人,不断循环,直到剩下最后一个人

例如:

[1,2,3,4,5,6,7,8,9,10] // 左到右删奇数位
->[2,4,6,8,10] // 反向删奇数位
->[4, 8] // 左到右删奇数位
->[8] return 8

还是抽象化问题,抓住本质——每次删除元素后得到新的等差数列,确定首项和公差就可以确定一切

  • 奇数轮删除,从左向右删奇数位,那么第二个数变成删除后的第一个数。公差翻倍
  • 偶数轮删除,反向删除奇数位,如果删除前元素总个数是偶数,那么首项不变,否则原次项变成新首项。公差翻倍
class Solution:
    def lastRemaining(self, n: int) -> int:
        # 每次总要删除一半或者一半+1的数,即总会剩下n//2个数
        psuedo_len = n
        round = 0
        first = 1
        second = 2
        delta  = 1
        while psuedo_len != 1:
            round += 1
            # 奇数轮删除(从左向后,第二个数变成删除后的第一个数)
            if round % 2 == 1:
                first = second
            # 偶数轮删除(从右向左删)
            else:
                if psuedo_len % 2 == 0:
                    # 删除后的第一个数不变
                    pass
                else:
                    # 第二个数变成删除后的第一个数
                    first = second     
            delta = 2*delta
            second = first + delta
            psuedo_len = psuedo_len // 2
        return first

现在回过头来,我们可以给玩法1也做类似的解答

class Solution:
    def lastRemaining(self, n: int) -> int:
        psuedo_len = n
        round = 0
        first = 1
        second = 2
        delta  = 1
        while psuedo_len != 1:
            round += 1
            first = second
            delta = 2*delta
            second = first + delta
            psuedo_len = psuedo_len // 2
        return first

相关文章

  • last one to survive 2022-01-03(未

    本文来自于对leetcode #### 390. 消除游戏[https://leetcode-cn.com/pro...

  • 每日一句

    One has to adapt to survive. 要想生存,就要学会适应。

  • 因为爱而存在

    All we need to survive is one person who truly loves us. ...

  • Last one ,This one

    (十四行诗) 无论是活着,亦或死去 是坠落还是升腾 一如夏花般凋零与灿烂 他靠近大海;他向往朝阳 天空...

  • The last one

    我站在镜子前,镜里的人却不是我,正当我要仔细去看的时候,梦醒了。 我在一个船舱中,叫醒我的是邻床的小七,他只有19...

  • no last one

    有时候觉得活着很累 有时候却总给自己放假 年轻时候的我们啊 总会一脸无辜的装疯卖傻 还说些虚伪的情话 羡慕那些一如...

  • last one

    最后一周了,这周我突然被加进公司核心群了,说实话,惊讶且心寒,来公司一年了,里面有两个人比我还迟来公司,虽然群里没...

  • last one

    你态度这么明确,我也不自欺欺人了。

  • How social media endangers knowl

    WIKIPEDIA, ONE OF the last remaining pillars of the open ...

  • UX Study Note 2: Usability &

    Last study notesummarized that one of the key factors of ...

网友评论

      本文标题:last one to survive 2022-01-03(未

      本文链接:https://www.haomeiwen.com/subject/wjefcrtx.html