有20我的圍城一圈(編號0~19),從第0號的人從8開始報數,凡報到3的倍數的人離開圈子,而後再繼續數下去,直到最後剩下兩人爲止,剩餘這兩人原來的位置是多少號?

需求

  話很少說,直接上需求,如題。python

'''
有20我的圍城一圈(編號0~19),從第0號的人從8開始報數,凡報到3的倍數的人離開圈子,而後再繼續數下去,直到最後剩下兩人爲止,剩餘這兩人原來的位置是多少號?
'''

思路

 

  拿到這個題,咱們先分析下,說是20我的圍成一圈,從0開始編號,0號位的人開始從8開始報數,3的倍數的直接出局,報數嘛,就是自增1唄。重點是循環報數,找到最後的兩我的,其實剩幾我的均可以,原理上都是同樣的,只是最後的判斷條件改個參數而已。迴歸正題,既然是循環報數,那麼就能夠想到遞歸,重複的調用函數體,這樣別說是20個,就算是2000我的也能夠找得出來,重點是不能超過python的最大遞歸深度。函數

  這裏呢,我把這20我的的位號寫進一個列表裏。這裏須要注意的是不能直接循環原列表來進行判斷刪除,由於在python裏邊,刪除中間的一個元素的話,後邊的會遇上來,這樣從刪除的第一元素後邊的全部的位號都是錯誤的,這樣最終的確定也得不到正確的結果。優化

  大概的思路分析就到這裏,下來咱們用python代碼來實現下。spa

代碼

# 生成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,時間複雜度空間複雜度都不最後化,僅供參考使用。很定也會有大佬能寫出更優化的代碼。code

  這道題也算是比較經典了,網上也有不少大佬用其餘語言實現了,因爲我只精通python,就用py代碼實現下,若是有其餘什麼問題,歡迎各位大佬前來指導交流。blog

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息
相關文章