我正在尝试找到一种最有效的方法来查找一组“0' 0”的排列。和' 1'给出一个索引。
Ex:给定l = [0,0,1,1]。以升序排列的所有排列是{0011,0101,0110,1001,11010,1100}。这些元素从0 - >开始索引。 5.给定index = 2,结果为0110。
我发现算法here输入整数多重集(例如l = [1,2,2])。他的算法是有效的(O(N ^ 2))。但是,我的multiset只包含' 0' 0和' 1'并且要求O(N)或更少。 N是列表的长度
请你帮助我。请注意,我的实际测试很大(len(l)是1024),因此intertool库不适合。我试图尽可能加快它(例如,使用gmpy2 ......)
基于1,以下是我的尝试,但它是O(N ^ 2)
from collections import Counter
from math import factorial
import gmpy2
def permutation(l, index):
if not index:
return l
counter = Counter(l)
total_count = gmpy2.comb(len(l), counter['1'])
acc = 0
for i, v in enumerate(l):
if i > 0 and v == l[i-1]:
continue
count = total_count * counter[v] / len(l)
if acc + count > index:
return [l[i]] + permutation(l[:i] + l[i + 1:], index - acc)
acc += count
raise ValueError("Not enough permutations")
l = ['0', '0', '1', '1']
index = 2
print (l, index)
--> result = [0, 1, 1, 0]
提前致谢。
答案 0 :(得分:3)
让我们思考:
For n bits with k ones there are n choose k anagrams.
For each position, p, that the i`th left-most set-bit can occupy there are
p choose (k-i) anagrams, for example:
n = 4, k = 2, i = 1 (left-most set-bit), position 1 => 001x => 1 choose 1 = 1
n = 4, k = 2, i = 1 (left-most set-bit), position 2 => 01xx => 2 choose 1 = 2
Given index 3 (non zero-based), we calculate the position of the
left-most set-bit:
position 1, 1 choose (2-1) = 1 anagram, index 1
position 2, 2 choose (2-1) = 2 anagrams, index 2-3
We now know the left-most set-bit must be on position 2 and we know there
are 2 anagrams possible.
We look at the next set-bit (i = 2):
position 0, 0 choose (2-2) = 1 anagram, index 2
position 1, 1 choose (2-2) = 1 anagram, index 3
Therefore the second set-bit is in position 1 => 0110
I think this might be O(n*k) - I hope someone can understand/explain the
complexity better and perhaps improve/optimize this algorithm idea.
答案 1 :(得分:3)
给定N 0和M 1的排列,我们需要找到索引为K的排列
我们知道从0开始的排列数等于N-1 0和M 1的排列数,我们称之为K0。
if K > K0 => The permutation starts with 1, K remains the same
if k <= K0 => The permutation starts with 0, remove K0 from K
修复第一位,然后以K = K - K0和正确的0和1数重新开始。
该算法在O(n)中运行,其中n是位数(而不是列表的长度)。
为了简化计算,我们假设基于1的索引(从1开始)
示例:
n = xxxx
l = [0, 0, 1, 1]
K = 2 => 3
Number of permutations starting with 0: K0 = 3! / (2! * 1!) = 3
K <= K0 => first bit is a 0
n = 0xxx
l = [0, 1, 1]
K = K = 3
Number of permutations starting with 0: K0 = 2! / (2! * 0!) = 1
K > K0 => first bit is a 1
n = 01xx
l = [0, 1]
K = K - K0 = 2
Number of permutations starting with 0: K0 = 1! / (1! * 0!) = 1
K > K0 => first bit is a 1
n = 011x
l = [0]
K = K - K0 = 1
Number of permutations starting with 0: K0 = 1! / (0! * 0!) = 1
K <= K0 => first bit is a 0
n = 0110 Which is verified in your example.
实现此算法可能很棘手,请确保正确处理整个列表仅由0或1组成的情况。计算阶乘也可能需要一段时间(并导致其他语言溢出),但可以预先计算它们。
答案 2 :(得分:2)
有些想法可以尝试解决这个问题。
这是一个打印所有排列的简单程序:
import sys
oneBits = int(sys.argv[1])
totalLen = int(sys.argv[2])
low = 2**oneBits-1
end = 2**totalLen
print 'oneBits:',oneBits
print 'totalLen:',totalLen
print 'Range:',low,'-',end
print
format = '{0:0%db}' % totalLen
index = 0
print 'Index Pattern Value'
for i in range(low,end):
val = format.format(i)
if val.count('1') == oneBits:
print '%5d %s %5d' % (index,val,i)
index += 1
正如你所看到的,它完全依赖于位操作(好吧,我在计算1
位时有点作弊: - )
当您使用各种输入运行它时,您将看到输入具有模式:
oneBits: 2
totalLen: 5
Range: 3 - 32
Index Pattern Value
0 00011 3
1 00101 5
2 00110 6 <-- pure shift
3 01001 9
4 01010 10
5 01100 12 <-- pure shift
6 10001 17
7 10010 18
8 10100 20
9 11000 24 <-- pure shift
所以我的第一个方法是找出这些纯粹转变发生的指标。距离仅取决于0和1位的数量。由于总和始终为1024,这意味着您应该能够预先计算这些点并将结果存储在包含1024个条目的表中。这将使您接近您想要的位置。
答案 3 :(得分:1)
根据Samy Arous的想法,我改变了他的alg:
if K >= K0 => The permutation starts with 1, K = K - K0
if K < K0 => The permutation starts with 0, K remains the same
以下是我的代码:
import gmpy2
def find_permutation (lst, K, numberbit1, numberbit0):
l = lst
N = numberbit0
M = numberbit1
if N == len(l):
return '1' * N
if M == len(l):
return '1' * M
result = ''
for i in range (0, len(lst)-1):
K0 = gmpy2.comb(len(l)-1, M)
if (K < K0):
result += '0'
l.remove ('0')
else:
result += '1'
l.remove ('1')
M -=1
K = K - K0
result += l[0]
return result
lst = ['0','1','1', '1']
K = 1
numberbit1 = 3
numberbit0 = 1
print find_permutation (lst, K, numberbit1, numberbit0)
--> result = '1011'
谢谢。虽然它是O(n)x(gmpy2.comb的复杂性),但它比我的问题中的alg要好。