《Python算法竞赛攻略:从入门到降维打击》——第十二章

第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,程序也必然会超时。在使用前,请务必先用数学公式(如

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱看烟花的码农

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值