話很少說,直接上需求,如題。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