第4章-18 猴子选大王
- 分析
- 题目
- 解法
- 改进:使用pop()函数实现
- `while(True):`改进后:
- 对于`len(lst)>1`作为while判断的条件
- 极简代码,约瑟夫环问题
分析
按数目,建立一个全为1的列表,cnt计数,如果mod3为0,就修改列表对应值为0。使用求和sum,判断如果只有一个1,就是结果。
从头到尾不断循环,这就要考虑while循环,同时一定要注意程序有退出出口:break
程序退出的条件,其实是在不断检索中。安插在赋值为0后。进行if判断。
题目
一群猴子要选新猴王。新猴王的选择方法是:让N只候选猴子围成一圈,从某位置起顺序编号为1~N号。从第1号开始报数,每轮从1报到3,凡报到3的猴子即退出圈子,接着又从紧邻的下一只猴子开始同样的报数。如此不断循环,最后剩下的一只猴子就选为猴王。请问是原来第几号猴子当选猴王?
输入格式:
输入在一行中给一个正整数N(≤1000)。
输出格式:
在一行中输出当选猴王的编号。
解法
n=int(input())
lst=[]
cnt=0
for i in range(1,n+1):
lst.append(1)
while True:
if sum(lst)!=1:
for i in range(n):
if lst[i]==1:
cnt+=1
if cnt%3==0:
lst[i]=0
cnt=0
else:
for i in range(n):
if lst[i]==1:
print(i+1)
break
实际上,只需要在每次修改赋值为0之后使用判断语句即可。
n=int(input())
lst=[]
cnt=0
flag=0
for i in range(1,n+1):
lst.append(1)
while True:
for i in range(n):
if lst[i]==1:
cnt+=1
if cnt%3==0:
lst[i]=0
if sum(lst)==1:
for i in range(n):
if lst[i]==1:
print(i+1)
flag=1
break
if flag==1:
break
运行超时,应该是有特别的输入,导致一直循环。
特别的:
if n==1:
print(1)
n=int(input())
lst=[]
cnt=0
flag=0
for i in range(1,n+1):
lst.append(1)
while True:
for i in range(n):
if lst[i]==1:
cnt+=1
if cnt%3==0:
lst[i]=0
if sum(lst)==1:
for i in range(n):
if lst[i]==1:
print(i+1)
flag=1
break
if flag==1:
break
if n==1:
print(1)
break
改进:使用pop()函数实现
n=int(input())
if n==1:
print(1)
exit(0)
lst=[]
cnt=0
time=0
flag=0
for i in range(1,n+1):
lst.append(i)
while True:
cnt+=1
time+=1
for i in range(n):
if cnt>len(lst):
cnt=1
if time==3:
time=0
lst.pop(cnt-1)
cnt-=1
if len(lst)==1:
print(lst[0])
flag=1
break
if flag==1:
break
这个解法错误的原因是while循环已经实现了,内部不需要再嵌套for循环,而且lst内的数据是动态变化的,range(n)已经失去了作用,而且for循环内并没有实现对cnt和time的++。
n=int(input())
if n==1:
print(1)
exit(0)
lst=[]
cnt=0
time=0
flag=0
for i in range(1,n+1):
lst.append(i)
while True:
cnt+=1
time+=1
for i in range(n):
if cnt>len(lst):
cnt=1
if time==3:
time=0
lst.pop(cnt-1)
cnt-=1
if len(lst)==1:
print(lst[0])
flag=1
break
if flag==1:
break
while(True):
改进后:
n=int(input())
if n==1:
print(1)
exit(0)
lst=[]
cnt=0
time=0
flag=0
for i in range(1,n+1):
lst.append(i)
while True:
cnt+=1
time+=1
if cnt>len(lst):
cnt=1
if time==3:
time=0
lst.pop(cnt-1)
cnt-=1
if len(lst)==1:
print(lst[0])
flag=1
break
对于len(lst)>1
作为while判断的条件
n=int(input())
if n==1:
print(1)
exit(0)
lst=[]
cnt=0
time=0
flag=0
for i in range(1,n+1):
lst.append(i)
while(len(lst)>1):
time+=1
cnt+=1
if(cnt>len(lst)):
cnt=1
if(time==3):
time=0
lst.pop(cnt-1)
cnt-=1
print(lst[0])
极简代码,约瑟夫环问题
#zjuvegetable
#zjuvegetable:约瑟夫环问题,转化成线性问题,不然运行会超时,第二个检测点是n==1的情况,与一般不同
n=int(input())
if n == 1:
print(1)
else:
monkey=[i for i in range(1,n+1)]
while len(monkey) >= 3:
monkey.pop(2)
monkey.append(monkey.pop(0))
monkey.append(monkey.pop(0))
print(monkey[1])
醉里拈花 我理解是这样的:把从头重复报数的问题拆成一次一次的列表执行:例如四只猴子分别编号1 2 3 4 当猴子数量大于等于三只时(因为是关于3的循环)monkey.pop(2)就是把报数为三的第三只猴子出栈【注意索引从0开始,因此这里的2就是指第三只猴子】;然后为了保证本质上的环形不变,就把出栈的那只猴子的前面的两只猴子加入到线性队列的末尾【这样在逻辑上是形成了环形】;然后while循环是控制重复报数直至剩下两只猴子;而最后剩下的两只猴子一定是偶数的第二只胜出【即队列的第二个索引的1】(小白见解,如有错误望大佬们提点!(^-^))