给定一个字符串,找到最长子字符串的长度而不重复字符。
示例:
鉴于“abcabcbb”,答案是“abc”,长度为3。
int lengthOfLongestSubstring(char* s) {
if (s == NULL) {
return 0;
}
myHash hash;
int start = 0;
int end = 0;
int maxLen = 0;
while (s[end] != '\0') {
char c = s[end];
if (hash.find(c) == hash.end()) {
hash[c] = end;
end++;
}else {
if (end - start > maxLen) {
maxLen = end - start;
}
int index = hash[c];
while(start <= index) {
hash.erase(s[start]);
start++;
}
}
}
if (end - start > maxLen) {
maxLen = end - start;
}
return maxLen;
}
有人说这个算法复杂度是O(n),但我认为它不考虑第二个循环,它小于O(n ^ 2)但应该大于O(n)。
我们应该如何分析最坏情况的复杂性?
答案 0 :(得分:2)
该算法的复杂性确实是O(n)。
证明:考虑start
和end
的值。外循环的每次迭代都执行以下两种操作之一:
end
提前1或start
一次或多次。 end
提前的次数等于n
,即输入的长度。 <{1}}提前的总次数不能超过start
,因为n
永远不会设置为index
以上的数字,n
1}}永远不会减少。
因此,外循环运行的总次数为start
,内循环运行的总次数为n
,产生的时间复杂度为O(n)。
请注意,内部循环不会立即执行所有n
次迭代。它的迭代是&#34;分布式的#34;在外循环的迭代中。但是,如果总计内循环的迭代次数,则在外循环的所有迭代期间,它们不会超过n
。
答案 1 :(得分:2)
渐近复杂度分析比计算循环更棘手。
然而,在我们进一步讨论之前,请注意,如果算法的渐近复杂度为O(n),那么它也 O(n 2 ),后者表达了较弱的界限。想必你正在寻找最严格的约束。
现在让我们看看在外循环的所有迭代中执行的所有操作的总和。在每次迭代中,计算hash.find(c) == hash.end()
。我们假设每个这样的评估费用为O(1)。然后有两种选择:
当前字符s[end]
与当前子字符串中的所有其他字符不同,由哈希查找判断。在这种情况下,当前字符将添加到当前子字符串中,end
会递增。
当前字符复制当前子字符串中的前一个字符。在这种情况下,将从子字符串中删除当前字符和当前子字符串中每个前面字符的先前外观。
原始字符串中的每个n
字符都会被添加到当前字符串一次,并且最多从其中删除一次,并且每个字符的添加或删除所涉及的操作花费为O(1)。在外循环中执行的剩余操作每次迭代花费O(1)。循环的每次迭代都执行一次加法或至少一次删除,因此总共不能超过2 * n次迭代。这使得循环嵌套的最坏情况成本为n * O(1)
[对于添加] + n * O(1)
[对于删除] + 2 * n * O(1)
[对于其他操作],总成本由{{限制1}}。
答案 2 :(得分:1)
如果我理解您的算法和数据结构使用正确,请考虑更糟糕的情况:我们一遍又一遍地获得相同字符的字符串,并且每次都必须擦除。在这种情况下,我们对字符串执行了大约2n
个操作。这仍然是线性增长,在它面前有一个常数。因此,为了理解它是如何增长的,我们仍然是线性增长 - 但正如您所指出的那样,在n
和n^2
之间,因为我们关于{{1最坏情况。