约瑟夫环
问题描述:
约瑟夫环问题的基本描述如下:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为1的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,要求找到最后一个出列的人或者模拟这个过程。
解题思路:构建循环列表
def Josephuson(n, m): List = list(range(1, n + 1)) #生成n序列 index = 0 while List: temp = List.pop(0) #弹出列表的第一个值 index += 1 if index == m: print('{}-->'.format(temp), end='') #打印路径 index = 0 #索引重新归零 continue #索引符合m的倍数,结束本次循环,该值不在参与循环列表的构建 else: List.append(temp) #不满足索引条件把弹出来的数值重新添加到列表尾部构建循环列表 if len(List) == 1: # 当列表只有1个值时结束循环 print(List[0]) break if __name__ == '__main__': n = int(input('总人数:')) m = int(input('报数:')) Josephuson(n, m)
运行截图:
全排列
问题描述:输入一个字符串,按字典序打印出该字符串中字符的所有排列。
示例: 1 2 3的全排列如下:
1 2 3 , 1 3 2 , 2 1 3 , 2 3 1 , 3 1 2 , 3 2 1
从上面的全排列也可以看出来了,从左往右依次增大,对这就是字典序法。可是如何用算法来实现字典序法全排列呢?
2.1字典序算法
例:字典序法找124653的下一个排列
如果当前排列是124653,找它的下一个排列的方法是:
从这个序列中从右至左找第一个左邻小于右邻的数,如果找不到,则所有排列求解完成,如果找得到则说明排列未完成。
本例中将找到46,计4所在的位置为i,找到后不能直接将46位置互换,而又要从右到左到第一个比4大的数,本例找到的数是5,其位置计为j,将i与j所在元素交换125643,然后将i+1至最后一个元素从小到大排序(也可以说是反转,从643到346)得到125346,这就是124653的下一个排列。
def DictSort(value): global number s_end = len(value) - 1 #尾指针 p = s_end #右邻指针 q = p - 1 #左邻指针 while p != 0: if value[q] >= value[p]: #字符串左邻大于或等于右邻 q = q - 1 # 指针往左移动 p = p - 1 # 指针往左动动 else: i = q # 找到左邻小于右邻,记录索引 j = s_end # 右邻指针重新指向末尾 while value[i] >= value[j]: # 从右往左找,找到记录值value[i]小于右邻的值 j = j - 1 value[i], value[j] = value[j], value[i] # 找到了,交换列表中二者的值 value[i + 1:] = value[-1:i:-1] # 剩下的值进行反转 number = number + 1 # 执行次数加1 return 1 return 0 if __name__ == '__main__': str = input('请输入排序的字符串:') number = 1 #记录执行的次数 value = list(str) value.sort() print("第{}种排序:{}".format(number, ''.join(value))) # 第一次最小排序 flag = DictSort(value) while flag: print("第{}种排序:{}".format(number,''.join(value)) ) flag = DictSort(value) print('该字符串一共有{}种排序!'.format(number))
运行效果截图:
2.2全排列递归实现
全排列的递归实现解析:
为方便起见,用123来示例下。123的全排列有123、132、213、231、312、321这六种。
1、首先考虑213和321这二个数是如何得出的。显然这二个都是123中的1与后面两数交换得到的。
2、然后可以将123的第二个数和每三个数交换得到132。同理可以根据213和321来得231和312。
3、因此可以知道——全排列就是从第一个数字起每个数分别与它后面的数字交换。
# 递归回溯实现字符串全排列 def AllSort(value, s, length): global number if s == length: # 递归出口 number = number + 1 print("第%d中排序:" % number, ''.join(value)) else: for i in range(s, length): value[s], value[i] = value[i], value[s] AllSort(value, s + 1, length) value[s], value[i] = value[i], value[s] #注意,因为递归有回溯的过程,所以需要把数字重新调换回来变为初始的排列。 if __name__ == '__main__': str = input('请输入排序的字符串:') number = 0 value = list(str) # 字符串转列表处理 length = len(value) value.sort() AllSort(value, 0, length)
运行效果截图
以上递归算法算然实现了全排列,但并非字典序,而且当字符串出现相同字符时,会出现相同的排列,所以如何优化呢?
优化方案:交换前先进行判断是否重复
def is_same(value, s, i): # 判断排列的重复性 while s < i: if value[s] == value[i]: return 0 s += 1 return 1 def AllSort(value, s, length): global number if s == length: #递归出口 number = number + 1 print("第%d中排序:" % number, ''.join(value)) else: for i in range(s, length): if is_same(value, s, i): #去重全排列 value[s], value[i] = value[i], value[s] AllSort(value, s + 1, length) value[s], value[i] = value[i], value[s] if __name__ == '__main__': str = input('请输入排序的字符串:') number = 0 value = list(str) length = len(value) value.sort() AllSort(value, 0, length)
运行效果截图: