• 有20个人围成一圈(编号0~19),第0号的人从8开始报数,凡报到3的倍数的人离开圈子,然后再继续数下去,直到最后剩下两人为止,剩余这两人原来的位置是多少号?


    需求

      话不多说,直接上需求,如题。

    '''
    有20个人围成一圈(编号0~19),第0号的人从8开始报数,凡报到3的倍数的人离开圈子,然后再继续数下去,直到最后剩下两人为止,剩余这两人原来的位置是多少号?
    '''

    思路

      拿到这个题,我们先分析下,说是20个人围成一圈,从0开始编号,0号位的人开始从8开始报数,3的倍数的直接出局,报数嘛,就是自增1呗。重点是循环报数,找到最后的两个人,其实剩几个人都可以,原理上都是一样的,只是最后的判断条件改个参数而已。回归正题,既然是循环报数,那么就可以想到递归,重复的调用函数体,这样别说是20个,就算是2000个人也可以找得出来,重点是不能超过python的最大递归深度。

      这里呢,我把这20个人的位号写进一个列表里。这里需要注意的是不能直接循环原列表来进行判断删除,因为在python里边,删除中间的一个元素的话,后边的会赶上来,这样从删除的第一元素后边的所有的位号都是错误的,这样最终的肯定也得不到正确的结果。

      大概的思路分析就到这里,下来我们用python代码来实现下。

    代码

    # 生成20个人的座位号
    l = [i for i in range(20)]
    
    li = l[:]  # 将原始的座位号copy一份出来
    n = 8  # 报数的起始数
    
    
    def f(n, li):
        '''
        递归查找最后的两个人
        :param n: 每轮的起始报数值
        :param li: 每轮起始的剩余人的座位号列表
        :return: 每轮剩余的人的座位号列表
        '''
        for i in li:
    
            # 判断当前报数是否为3的倍数,是的话该人直接出局
            if n % 3 == 0:
                l.remove(i)
    
            # 判断列表中还剩多少人,剩余2人终止递归
            if len(l) == 2:
                return l
    
            n += 1  # 报数自增1
    
        li = l[:]  # 一次递归调用后剩下的人,copy一份数据供下次递归使用
    
        return f(n, li)
    
    
    print(f(n, li))

      以上就是py代码的实现,这个代码呢写的也很low,时间复杂度空间复杂度都不最优化,仅供参考使用。肯定也会有大佬能写出更优化的代码。

      这道题也算是比较经典了,网上也有很多大佬用其他语言实现了,由于本人只精通python,就使用py代码实现下,如果有其他什么问题,欢迎各位大佬前来指导交流。

  • 相关阅读:
    Python 标准库 urllib2 的使用细节
    为什么C++编译器不能支持对模板的分离式编译
    source insight插件
    tar命令
    绘制和重绘,有效矩形和无效矩形
    常量表达式
    区间迭代
    lambda函数
    decltype和新的返回值语法
    auto用法
  • 原文地址:https://www.cnblogs.com/ZN-225/p/11161372.html
Copyright © 2020-2023  润新知