第12章:Pythonic效率工具箱
12.1 itertools: 排列、组合、笛卡尔积的数学之美
在算法竞赛中,我们经常遇到涉及排列组合的搜索问题。例如,“从N个物品中选取M个的所有方案”、“对一组元素进行全排列”等等。在C++中,这通常需要我们手写复杂的递归函数,不仅耗时,还容易出错。而Python的itertools模块,将这些基础的数学概念封装成了高效、简洁的工具,让我们能一行代码解决问题,专注于算法逻辑本身。
核心理念: 不要手动实现轮子,itertools就是你最可靠的数学工具。
1. 笛卡尔积 (itertools.product)
-
功能: 计算多个可迭代对象的笛卡尔积。它等价于多重嵌套循环。
-
应用场景: 当你需要从多个独立的集合中各取一个元素,组成所有可能的组合时。例如,多颗骰子的点数组合、多件不同部位装备的搭配方案等。
-
实战案例:
假设有3个密码盘,第一个盘有数字[1, 2],第二个盘有字母['A', 'B'],第三个盘有符号['#', '*']。求所有可能的密码组合。import itertools p1 = [1, 2] p2 = ['A', 'B'] p3 = ['#', '*'] # 使用itertools.product计算笛卡尔积 for password in itertools.product(p1, p2, p3): print(password) # 输出: # (1, 'A', '#') # (1, 'A', '*') # (1, 'B', '#') # (1, 'B', '*') # (2, 'A', '#') # (2, 'A', '*') # (2, 'B', '#') # (2, 'B', '*')降维打击效果: 仅用一行
itertools.product(p1, p2, p3)就替代了三层嵌套的for循环,代码意图一目了然。
2. 排列 (itertools.permutations)
-
功能: 从一个可迭代对象中,取出指定数量的元素进行全排列。
-
应用场景: 解决需要考虑“顺序”的问题。例如,N个人排队的所有排法、用数字1,2,3组成所有可能的三位数。
-
实战案例:
给定一个数组[1, 2, 3],输出其所有长度为3的全排列。import itertools nums = [1, 2, 3] # 计算长度为3的全排列 for p in itertools.permutations(nums, 3): # r参数可选,默认为len(nums) print(p) # 输出: # (1, 2, 3) # (1, 3, 2) # (2, 1, 3) # (2, 3, 1) # (3, 1, 2) # (3, 2, 1)降维打击效果: 无需编写递归和
visited数组,一行代码即可优雅地生成全排列。
3. 组合 (itertools.combinations)
-
功能: 从一个可迭代对象中,取出指定数量的元素进行组合,不考虑顺序。
-
应用场景: 解决不考虑“顺序”的选取问题。例如,从N个人中选M个人组成委员会、从一堆数中选出两个数求和。
-
实战案例:
在一个数组[1, 2, 3, 4]中,找出所有大小为2的组合。import itertools nums = [1, 2, 3, 4] # 计算大小为2的组合 for c in itertools.combinations(nums, 2): print(c) # 输出: # (1, 2) # (1, 3) # (1, 4) # (2, 3) # (2, 4) # (3, 4)降维打击效果: 对于组合问题,
itertools.combinations是无可替代的最优解,避免了为保证顺序而设计的复杂循环或递归。
4. 可重复组合 (itertools.combinations_with_replacement)
- 功能: 类似组合,但允许同一个元素被多次选择。
- 应用场景: 可重复的选取问题。例如,从3种口味的冰淇淋中买2个球,可以买两个相同口味的。
竞赛提示:
itertools返回的是一个迭代器,而不是列表。这意味着它在内存使用上极为高效,只有在你遍历它的时候才会逐个生成元素。但是,如果排列组合的总数巨大(例如对20个元素全排列),即使使用itertools,程序也必然会超时。在使用前,请务必先用数学公式(如

最低0.47元/天 解锁文章

被折叠的 条评论
为什么被折叠?



