gpt4 book ai didi

python - 在 `itertools` Python 模块返回的组合中查找给定组合(自然数)的索引

转载 作者:太空狗 更新时间:2023-10-29 21:58:49 28 4
gpt4 key购买 nike

给定前 n 个自然数的 k 组合,出于某种原因,我需要在 itertools 返回的那些组合中找到这种组合的位置。 combination(range(1,n),k)(原因是这样我可以使用 list 而不是 dict 来访问关联的值每个组合,知道组合)。

因为 itertools 以规则的模式产生它的组合,所以可以这样做(而且我还发现了一个简洁的算法),但我正在寻找一种更快/更自然的方式,我可能忽略。

顺便说一句,这是我的解决方案:

def find_idx(comb,n):
k=len(comb)
idx=0
last_c=0
for c in comb:
#idx+=sum(nck(n-2-x,k-1) for x in range(c-last_c-1)) # a little faster without nck caching
idx+=nck(n-1,k)-nck(n-c+last_c,k) # more elegant (thanks to Ray), faster with nck caching
n-=c-last_c
k-=1
last_c=c
return idx

其中 nck 返回 binomial coefficient of n,k .

例如:

comb=list(itertools.combinations(range(1,14),6))[654] #pick the 654th combination
find_idx(comb,14) # -> 654

这是一个等价但可能较少涉及的版本(实际上我从下一个推导出前一个)。我将 c 组合的整数视为二进制数字中 1 的位置,我在解析 0/1 时构建了一个二叉树,并且在解析过程中发现了索引递增的规律模式:

def find_idx(comb,n):
k=len(comb)
b=bin(sum(1<<(x-1) for x in comb))[2:]
idx=0
for s in b[::-1]:
if s=='0':
idx+=nck(n-2,k-1)
else:
k-=1
n-=1
return idx

最佳答案

您的解决方案似乎很快。在 find_idx 中,您有两个 for 循环,可以使用以下公式优化内部循环:

C(n, k) + C(n-1, k) + ... + C(n-r, k) = C(n+1, k+1) - C(n-r, k+1)

因此,您可以将 sum(nck(n-2-x,k-1) for x in range(c-last_c-1)) 替换为 nck(n-1 , k) - nck(n-c+last_c, k).

我不知道你是如何实现你的nck(n, k) 函数的,但它的时间复杂度应该是O(k)。这里我提供我的实现:

from operator import mul
from functools import reduce # In python 3
def nck_safe(n, k):
if k < 0 or n < k: return 0
return reduce(mul, range(n, n-k, -1), 1) // reduce(mul, range(1, k+1), 1)

最后,您的解决方案在没有递归的情况下变为 O(k^2)。它非常快,因为 k 不会太大。

更新

我注意到 nck 的参数是 (n, k)。 n 和 k 都不会太大。我们可以通过缓存来加速程序。

def nck(n, k, _cache={}):
if (n, k) in _cache: return _cache[n, k]
....
# before returning the result
_cache[n, k] = result
return result

在 python3 中,这可以通过使用 functools.lru_cache 装饰器来完成:

@functools.lru_cache(maxsize=500)
def nck(n, k):
...

关于python - 在 `itertools` Python 模块返回的组合中查找给定组合(自然数)的索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14455634/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com