程序员必备算法,排列组合

还记得排列组合吗?
在高中的时候最常接触的莫过于排列组合了,毕竟高考必考的嘛。咱们先来回忆下这两个的公式是啥:
3e680003579fdd984fd5
排列组合公式
若是看到这个还有一丢丢的印象,说明你们的基础都还不错。那么问题来了,你们都是学计算机的,咱们如何用程序去模拟这个过程,从而达到列出全部排列组合的可能呢?
全排列的实现
暴力求解(不可取,不可取)
相信不少初入门的小伙伴首先想到的就是就是直接经过嵌套多个for循环去遍历不就行了,只要不相等就直接输出,就像下面这样:css

def force(): data = "abc"
for i in range(len(data)): for j in range(len(data)): for k in range(len(data)): if data[i] != data[j] and data[j] != data[k] and data[k] != data[i]:
print(data[i],data[j],data[k])if __name__ == '__main__':
force()/*输出
 a b c
 a c b
 b a c
 b c a
 c a b
 c b a
*/

看上去还能够的样子,不过这样有几个坏处,若是不想全排列 abc 了,而是想对 abcd 进行全排列了,那么咱们必需要修改源代码增长一个for循环,并且若是排列的数不少的话,那这个循环也太多了吧。
递归求解
上面这种解法实在有点不优雅,那么咱们如何在不修改源码的状况下就能够求出全部的排列组合状况呢?
解决全排列的重复问题
细心的小伙伴确定会发现,上面的代码实际上是有问题的,若是排列的数组中有重复的元素那么结果中也会有重复的排列,这是咱们不但愿看到的。那么咱们如何解决这个问题呢?
要想解决这个问题,咱们首先须要知道这个问题是怎么来的,仍是参考刚刚的图,咱们稍微修改下:
3e68000357a268d39a72html

对于 abc 的排列,当咱们进行排列时,能够先考虑第1位可能有哪些状况,如上图所示有a,b,c三种状况,而后再对后面的两位进行排列,采用相同的思路,因此咱们能够很容易的就经过递归实现全排列了。前端

def rank(data, step): if len(data) == step+1:
print(data) return
else: for i in range(step, len(data)): data[step], data[i] = data[i], data[step] //让当前首位依次为后面的每个数
rank(data, step + 1) //递归后面的状况
data[step], data[i] = data[i], data[step]if __name__ == '__main__': data = list("abc")
rank(data, 0)

运行上面的代码,能够获得和上面暴力求解一毛同样的结果,且此次若是须要对其余状况进行全排列不须要再修改源代码,且只用了一个循环(虽然用递归效率还不如多个循环^-^),不过至少代码看上去仍是很优雅的。
3eb20001d52e8fd26277程序员

就拿 cac 这个举个栗子:
当以第一个c为开头时,咱们须要对 ac 进行全排列,没问题
当以a为开头时,咱们须要对 cc 进行全排列,没问题
当以第二个c为开头时,咱们须要对 ca 进行全排列,这就有问题了,ac和ca的全排列不就同样的嘛,并且开头也同样,这个确定就会有重复了呀,咱们对源码稍加修改下:web

def is_equal(data,left,right): #判断left到当前right是否有相等的,若是有说明以前已经对这
for i in range(left,right): #个进行过全排序了
if data[i] == data[right]: return True
return Falsedef rank(data, step):
if len(data) == step+1:
print(data) return
else: for i in range(step, len(data)): if is_equal(data,step,i): #加一个判断
continue
else:
data[step], data[i] = data[i], data[step]
rank(data, step + 1)
data[step], data[i] = data[i], data[step]if __name__ == '__main__':
data = list("bcc")
rank(data, 0)

ok,这样运行上面的代码的就不会有重复的问题了,这里可能须要小伙伴们多思考下了,不过仍是很简单的。
组合问题
问题描述
加入我有一个数组 [1, 2, 3, 4, 5, 6] ,我想从里面随机选出三个来,问有哪些取法。
解决思路
一样是递归,由于咱们也不知道循环的具体次数嘛,可是要如何递归呢?
3e6b000330615701fe68面试

不要急,假设咱们要从上面的数组中选出3个元素出来。
咱们首先从第一个元素下手,对于第一个元素,咱们有两个选择:要 or 不要。
若是要了,那么咱们须要选择的元素就少了一个了,咱们只须要从后面的元素中选出两个就够了。
若是不要,咱们就从第二个元素继续看,此时咱们仍是要选出三个(原本想画图演示的,不过这个图好像有点复杂,笔者画图实在是个菜鸟就偷会懒了)。算法

def combine(data, step, select_data, target_num):
if len(select_data) == target_num: #选择的元素已经够了,就输出并返回
print(select_data) return
if step >= len(data): #没有元素选了并且还没够,也是直接返回
return
select_data.append(data[step]) #选择当前元素
combine(data, step + 1, select_data, target_num)
select_data.pop() #别忘了从已选择元素中先删除
combine(data, step + 1, select_data, target_num) #不选择当前元素if __name__ == '__main__':
data = [1, 2, 3, 4, 5, 6]
combine(data, 0, [], 3)

运行上面的代码就能够得出全部的组合可能了,仍是比较优雅的。可是一样当数组中有重复元素的时候也会有重复的组合,这个如何解决呢?这个就让小伙伴们本身思考下吧。
总结
排列组合算法仍是很贴近咱们生活的,在各类算法,项目与面试中也会常常碰见,因此也算程序员必备算法了,上面代码若是有问题也欢迎小伙伴与笔者留言私信交流,一块儿学习交流一块儿进步。编程

“小编每晚都会讲解企业案例知识点,也有准备一份适合2018年学习的web前端教程,html+css+原生js到H5移动端及各类框架都有整理,送给每一位前端小伙伴,这里是暴走前端院,欢迎初学和进阶中的小伙伴。”
想要学习或者了解web前端编程的小伙伴,能够加群:575308719(学习交流/领取教程)

图片描述

相关文章
相关标签/搜索