符合区间要求的数组选数组合计数实现复杂度及优化咨询
问题解答
1 两种实现的最坏时间复杂度
我们先定义M为原数组筛选后符合[MIN, MAX]区间要求的元素个数,最坏情况下M=N(所有元素都符合区间要求)。
- 第一种暴力生成组合的实现:
最坏场景为K=1,需要生成所有长度从1到M的非空组合,总组合数为2^M - 1,每个组合生成时需要遍历对应长度的元素存入元组,总时间复杂度为O(M * 2^M),最坏可到O(N * 2^N),数组长度稍大就会严重超时。 - 第二种组合数求和的实现:
最坏场景为K=1,需要循环计算M次组合数,每次计算组合数NcR(n,r)的时间复杂度为O(min(r, n-r)),最坏单轮计算为O(M),总时间复杂度为O(M²),最坏可到O(N²),性能远优于暴力实现。
2 基于二项式特性的优化方案
完全可以利用你提到的二项式特性做优化,核心优化思路有两个:
2.1 用总组合数做差值减少计算量
根据二项式展开总和sum_{r=0}^M C(M,r) = 2^M,我们可以把要求的和转换为:sum_{r=K}^M C(M,r) = 2^M - sum_{r=0}^{K-1} C(M,r)
判断M-K+1和K的大小,选择计算次数更少的方式:如果K > M/2,就直接从K累加到M;如果K <= M/2,就计算0到K-1的和再用2^M减去,最多只需要计算floor(M/2)+1次组合数,计算量直接减半。
2.2 边界情况提前处理
- 如果
M < K,直接返回0,无需后续计算 - 如果
K=0,直接返回1 << M即可
优化后的代码示例
from math import gcd def count_valid_combinations(arr, MIN, MAX, K): # 第一步筛选符合区间的元素 temp_list = [x for x in arr if MIN <= x <= MAX] M = len(temp_list) # 提前处理边界 if M < K: return 0 if K == 0: return 1 << M def NcR(n, r): if r <0 or r >n: return 0 if (n - r < r): r = n - r p = 1 k = 1 while r: p *= n k *= r m = gcd(p, k) p //= m k //= m n -=1 r -=1 return p total = 1 << M # 选择计算量更小的累加方式 if K <= M // 2: # 算前K项的和再减 sum_prev = 0 for i in range(K): sum_prev += NcR(M, i) return total - sum_prev else: # 直接算从K到M的和 sum_target = 0 for i in range(K, M+1): sum_target += NcR(M, i) return sum_target
内容的提问来源于stack exchange,提问作者Mrinmay Dhar
相关产品推荐
相关产品推荐

