见很多大佬都是深知该题的数学规律,然后使用数学方法立项解题的,而我就不一样了,数学菜的一批,根本不知道往哪里找规律,就只能正面刚这道题
题目版本很多,大致意思都差不多,这里使用的是自己理解后的约瑟夫环问题的题目:
- 有n个人围成一圈,顺序排号
- 从第一个人开始报数(从1到3报数),报到3的人直接弄死,再从他的下一个人开始报数(从1到3报数)
问:最后留下的是哪位?
我先假设人共有10人,装进一个列表里:
list=[1,2,3,4,5,6,7,8,9,10]
通过纸和笔运算,很快就可以得到,天选之子为4号,有了思路后,开始分析:
第一个死的就是3号,打算使用list.pop()方法杀掉他,但是这个位置上的也不一定是3号,只要处在list[2]位置上的,就得死,所以杀掉报数为3的人的方法就是list.pop(list[2]),此时列表长度就少了一个人,同理,给位置一个参数num,然后让它自加2,杀掉下一个。
但这样下去,索引长度肯定会超过列表自身的长度的,因为每杀一个人,列表自身也在缩短一个单位,num总会大于list的长度的,所以要num-(len(list)-1),因为num是列表的位置,而列表本身与位置索引是相差1的,所以列表自身要减1,再给他们整体减1,才是需要的下一个报数为3的人的列表索引值,即num = (num - (len(list1) - 1)) - 1,理完思路了,就可以写代码了
l1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
def JosephRing(list1):
"""
主要方法为列表位置元素的删除、try的捕获IndexError后更新num的位置信息
:return:
"""
num = 2
while True:
try:
list1.pop(num)
num += 2
except IndexError:
if len(list1) == 1:
return l1[0] # 返回列表中的唯一一个值,即天选之子
else:
num = (num - (len(list1) - 1)) - 1 # 留意实际要删除的数据的位置
continue
if __name__ == '__main__':
print(JosephRing(l1))
# 输出结果
4
>>>