根据该文算法,改写为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] | 1048576 | 2.7s |
[1 : 21] | 2097152 | 5.7s |
[1 : 22] | 4194304 | 12s |
[1 : 23] | 8388608 | 25s |
[1 : 24] | 16777216 | 52s |
[1 : 25] | 33554432 | 109s |
[1 : 26] | 67108864 | 227s |
[1 : 27] | 134217728 | 472s |
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.7s | 0.66s |
[1 : 21] | 5.7s | 1.34s |
[1 : 22] | 12s | 2.68s |
[1 : 23] | 25s | 5.36s |
[1 : 24] | 52s | 10.89s |
[1 : 25] | 109s | 22s |
[1 : 26] | 227s | 43.82s |
[1 : 27] | 472s | 87.76s |