我正在尝试找到此algorithm的时间复杂度。
迭代:算法从输入的位串产生给定汉明距离内的所有位串。它生成所有递增的序列0 <= a[0] < ... < a[dist-1] < strlen(num)
,并在相应的索引处恢复位。
向量a
应该保留必须反转位的索引。因此,如果a包含当前索引i
,则我们打印1而不是0,反之亦然。否则我们按原样打印该位(参见else-part),如下所示:
// e.g. hamming("0000", 2);
void hamming(const char* num, size_t dist) {
assert(dist > 0);
vector<int> a(dist);
size_t k = 0, n = strlen(num);
a[k] = -1;
while (true)
if (++a[k] >= n)
if (k == 0)
return;
else {
--k;
continue;
}
else
if (k == dist - 1) {
// this is an O(n) operation and will be called
// (n choose dist) times, in total.
print(num, a);
}
else {
a[k+1] = a[k];
++k;
}
}
此算法的时间复杂度是什么?
我的尝试说:
dist * n +(n选择t)* n + 2
但这似乎不是真的,请考虑以下示例,所有示例均为dist = 2:
len = 3, (3 choose 2) = 3 * O(n), 10 while iterations
len = 4, (4 choose 2) = 6 * O(n), 15 while iterations
len = 5, (5 choose 2) = 9 * O(n), 21 while iterations
len = 6, (6 choose 2) = 15 * O(n), 28 while iterations
这是两个有代表性的运行(在循环开始时打印):
000, len = 3
k = 0, total_iter = 1
vector a = -1 0
k = 1, total_iter = 2
vector a = 0 0
Paid O(n)
k = 1, total_iter = 3
vector a = 0 1
Paid O(n)
k = 1, total_iter = 4
vector a = 0 2
k = 0, total_iter = 5
vector a = 0 3
k = 1, total_iter = 6
vector a = 1 1
Paid O(n)
k = 1, total_iter = 7
vector a = 1 2
k = 0, total_iter = 8
vector a = 1 3
k = 1, total_iter = 9
vector a = 2 2
k = 0, total_iter = 10
vector a = 2 3
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
gsamaras@pythagoras:~/Desktop/generate_bitStrings_HammDistanceT$ ./iter
0000, len = 4
k = 0, total_iter = 1
vector a = -1 0
k = 1, total_iter = 2
vector a = 0 0
Paid O(n)
k = 1, total_iter = 3
vector a = 0 1
Paid O(n)
k = 1, total_iter = 4
vector a = 0 2
Paid O(n)
k = 1, total_iter = 5
vector a = 0 3
k = 0, total_iter = 6
vector a = 0 4
k = 1, total_iter = 7
vector a = 1 1
Paid O(n)
k = 1, total_iter = 8
vector a = 1 2
Paid O(n)
k = 1, total_iter = 9
vector a = 1 3
k = 0, total_iter = 10
vector a = 1 4
k = 1, total_iter = 11
vector a = 2 2
Paid O(n)
k = 1, total_iter = 12
vector a = 2 3
k = 0, total_iter = 13
vector a = 2 4
k = 1, total_iter = 14
vector a = 3 3
k = 0, total_iter = 15
vector a = 3 4
答案 0 :(得分:3)
while循环有点聪明和微妙,可以说它做了两件不同的事情(如果算上a
的初始化,甚至可以算三件事)。这使得您的复杂性计算具有挑战性,并且效率也低于预期。
在摘要中,为了逐步计算当前索引的下一组索引,我们的想法是找到最后一个索引i
,它小于n-dist+i
,增加它,并将以下索引设置为a[i]+1
,a[i]+2
,依此类推。
例如,如果dist = 5,则n = 11且您的索引为:
0, 3, 5, 9, 10
然后5
是小于n-dist+i
的最后一个值(因为n-dist
是6,而10 = 6 + 4,9 = 6 + 3,但是5 <6 + 2)
因此我们递增5
,并设置后续整数以获取索引集:
0, 3, 6, 7, 8
现在考虑代码如何运行,假设k=4
0, 3, 5, 9, 10
a[k] + 1
为11,因此k
变为3。++a[k]
为10,因此a[k+1]
变为10,k
变为4。++a[k]
为11,因此k
变为3。++a[k]
为11,因此k
变为2。++a[k]
为6,因此a[k+1]
变为6,k
变为3。++a[k]
为7,因此a[k+1]
变为7,k
变为4。++a[k]
为8,我们继续调用print
函数。这段代码是正确的,但效率不高,因为k
在搜索可以递增而不会导致较高索引溢出的最高索引时向前和向后掠过。实际上,如果最高索引从最后开始是j
,则代码使用while循环的非线性数字迭代。如果您跟踪n==dist
对于n
的不同值的void hamming2(const char* num, size_t dist) {
int a[dist];
for (int i = 0; i < dist; i++) {
a[i] = i;
}
size_t n = strlen(num);
while (true) {
print(num, a);
int i;
for (i = dist - 1; i >= 0; i--) {
if (a[i] < n - dist + i) break;
}
if (i < 0) return;
a[i]++;
for (int j = i+1; j<dist; j++) a[j] = a[i] + j - i;
}
}
发生了多少次迭代,您可以自己轻松演示。只有一行输出,但是你会看到迭代次数增加了O(2 ^ n)(实际上,你会看到2 ^(n + 1)-2次迭代)。
这种破坏使你的代码不必要地低效,而且难以分析。
相反,您可以更直接地编写代码:
print
现在,每次通过while循环都会生成一组新的索引。每次迭代的确切成本并不简单,但由于{{1}}为O(n),而while循环中的剩余代码为最差O(dist),因此总成本为O(N_INCR_SEQ(n,dist) * n),其中N_INCR_SEQ(n,dist)是自然数的增加序列的数量&lt; n长度dist。评论中的某个人提供了一个链接,为此提供了一个公式。
答案 1 :(得分:1)
注意,给定n
表示长度,t
表示所需距离,t
整数1
之间的整数增加}和n
(或以0
和n-1
之间的索引形式)确实是n choose t
,因为我们选择t
个不同的索引。
生成这些系列会出现问题:
- 首先,请注意,例如在长度为4的情况下,您实际上会超过5个不同的索引,0到4。
- 其次,请注意您正在接受具有相同索引的帐户系列(在t=2
,其0 0, 1 1, 2 2
等情况下),通常情况下,您会查看每个非减少系列,而不是通过每个增加系列。
因此,为了计算程序的TC,请务必考虑到这一点。
提示:尝试从这些系列的宇宙中进行一对一的对应,以及对某些方程的整数解的范围。
如果您需要直接解决方案,请查看此处: https://math.stackexchange.com/questions/432496/number-of-non-decreasing-sequences-of-length-m
最终的解决方案是(n+t-1) choose (t)
,但是注意到程序中的第一个项目符号实际上是((n+1)+t-1) choose (t)
,因为你循环使用了一个额外的索引。
表示
((n+1)+t-1) choose (t) =: A
,n choose t =: B
总体而言,我们得到O(1) + B*O(n) + (A-B)*O(1)