python从数组中找出所有和为M的组合

根据该文算法,改写为python代码《改进,从一个数组中找出 N 个数,其和为 M 的所有可能》

按位运算

import time

def count_1(num):  # 计算二进制数中包含1的个数
    count = 0
    while num:
        if num & 1:  # 按位与运算,末尾为1则个数+1
            count += 1
        num >>= 1    # 按位右移动1,后赋值
    return count

def search(list, count, sum):
    # list待查找数值列表, count要求元素个数, sum待查找的和m
    length = len(list)  # 列表元素个数
    bin = 1 << (length-1)  # 判断二进制数1的位置使用,当前列表最大合适值
    res = []  # 空列表,存放 “和为sum的所有组合” 
    for i in range(1, 1 << length):  # 遍历所有组合(1-2的length次方减1)
        if count_1(i) == count:  # 判断组合内元素数量与count是否一致
            s = 0
            temp = []
            for k in range(0, length):  # 遍历该组合,对应列表
                if i & (bin >> k):  # 或if i & (1 << (length-1-k)):
                    s += list[k]
                    temp.append(list[k])
            if s == sum:
                res.append(temp)  # 将正确的组合嵌套至列表

    return res

#print(search([1,2,3,4], 2, 5))  # 结果[[2, 3], [1, 4]]

if __name__ == '__main__':
    start_time = time.time()
    list_100 = list(range(1,21))  # 1-20的列表
    print(search(list_100, 2, 15))
    end_time = time.time()
    print(end_time - start_time)  # 程序用时,秒

运行结果:
运行十分缓慢,列表每多一个元素,耗时翻一倍
以下为测试用时:

列表范围组合数耗时
[1 : 20]10485762.7s
[1 : 21]20971525.7s
[1 : 22]419430412s
[1 : 23]838860825s
[1 : 24]1677721652s
[1 : 25]33554432109s
[1 : 26]67108864227s
[1 : 27]134217728472s

按字符串运算

python代码按位运算缓慢,改为遍历组合字符串,运行速度得到明显提升,按理说按位运算速度是最快的,这就是python吗?

import time

def search(list, count, sum):
    # list待查找数值列表, count要求元素个数, sum待查找的和m
    length = len(list)  # 列表元素个数
    res = []  # 空列表,存放 “和为sum的所有组合” 
    bin = '{:0xb}'.replace('x', str(length))  # 二进制高位补0,二进制位数一致
    for i in range(1, 1 << length):  # 遍历所有组合(1-2的length次方减1)
        bin_str = bin.format(i)  # 将数值转为二进制
        if bin_str.count('1') == count:  # 判断组合内元素数量与count是否一致
            s = 0
            temp = []
            for k in range(0, length):  # 左闭右开,遍历该组合,对应列表
                if bin_str[k] == '1':
                    s += list[k]
                    temp.append(list[k])
            if s == sum:
                res.append(temp)  # 将正确的组合嵌套至列表

    return res

#print(search([1,2,3,4], 2, 5))  # 结果[[2, 3], [1, 4]]

if __name__ == '__main__':
    start_time = time.time()
    list_100 = list(range(1,21))  # 1-20的列表
    print(search(list_100, 2, 15))
    end_time = time.time()
    print(end_time - start_time)  # 程序用时,秒

运行结果:运行速度提高了4-5倍

列表范围原耗时现耗时
[1 : 20]2.7s0.66s
[1 : 21]5.7s1.34s
[1 : 22]12s2.68s
[1 : 23]25s5.36s
[1 : 24]52s10.89s
[1 : 25]109s22s
[1 : 26]227s43.82s
[1 : 27]472s87.76s
  • 1
    点赞
  • 8
    收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论

打赏作者

薛定谔_51

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

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值