我一直在阅读关于时间复杂性的阅读,并且我已经掌握了基础知识。为了强化这个概念,我看了一下我最近在这里给出的答案。现在问题已经结束了,但这不是重点。我无法弄清楚答案的复杂性是什么,在得到任何有用的反馈之前问题已经结束。
The task是找到字符串中的第一个唯一字符。我的回答很简单:
public String firstLonelyChar(String input)
{
while(input.length() > 0)
{
int curLength = input.length();
String first = String.valueOf(input.charAt(0));
input = input.replaceAll(first, "");
if(input.length() == curLength - 1)
return first;
}
return null;
}
我的第一个想法是,因为它查看每个角色,然后在replaceAll()
期间再次查看每个角色,它将是O(n ^ 2)。
然而,它让我思考它的实际运作方式。对于检查的每个字符,它然后删除字符串中该字符的所有实例。所以n
不断缩小。这是如何影响它的?这会使它成为O(log n),还是有些东西我没有看到?
我在问什么:
编写的算法的时间复杂度是什么?为什么?
我不是要问:
我不是在寻找改善它的建议。我知道可能有更好的方法来做到这一点。我试图更好地理解时间复杂性的概念,而不是找到最佳解决方案。
答案 0 :(得分:4)
您将遇到的最差时间复杂度是字符串aabb...
,因此每个字符重复两次。现在这取决于你的字母表的大小,假设是S
。我们还用L
注释初始字符串的长度。因此,对于每个字母,您将必须遍历整个字符串。但是,第一次执行此操作时,String的大小为L
,第二次为L-2
,依此类推。总的来说,假设L大于L + (L-2) + ... + (L- S*2)
,您必须按L*S - 2*S*(S+1)
次操作的顺序执行,即2*S
。
顺便说一句,如果你的字母表的大小是不变的,我想它是,你的代码的复杂性是O(L)
(尽管有一个很大的常量)。
答案 1 :(得分:1)
最坏的情况是O(n^2)
,其中n是输入字符串的长度。想象一下,除了最后一个角色之外,每个角色都加倍,例如“aabbccddeeffg”。然后有n / 2次循环迭代,每次调用replaceAll
都必须扫描整个剩余的字符串,这也与n
成比例。
编辑:正如Ivaylo所指出的,如果你的字母表的大小是不变的,那么技术上O(n)
是因为你从不考虑任何一个字符。
答案 2 :(得分:1)
让我们来标记:
m =单词
中唯一字母的数量
n =输入长度
这是复杂性计算:
主循环最多 m 次,因为有不同的字母,
.Replaceall在每个周期中检查最多O(n)个比较。
总数为:O(m * n)
O(m * n)循环的一个例子是:input = aabbccdd,
m = 4,n = 8
算法阶段:
1. input = aabbccdd, complex - 8
2. input = bbccdd, complex = 6
3. input = ccdd, complex = 4
4. input = dd, complex = 2
总= 8 + 6 + 4 + 2 = 20 = O(m * n)
答案 3 :(得分:1)
让m
为字母大小,让n
为字符串的长度。更糟糕的情况是在字母表字母之间统一分配字符串的字符,这意味着您的字母表中的每个字母都有n / m
个字符,让我们用q
标记此数量。例如,字符串aabbccddeeffgghh
是字母16
之间a-h
个字符的均匀分布,因此n=16
和m=8
都有q=2
每个字母的字符。
现在,你的算法实际上是越过字母表中的字母(它只是使用它们在字符串中出现的顺序),并且对于每次迭代,它必须越过字符串的长度(n
并按q
(n -= q
)缩小它。因此,在最坏的情况下,您所做的所有操作都是:
s = n + n-(1*q) + ... + n-((m-1)*q)
您可以看到s
是算术系列的第一个m
元素的总和:
s = (n + n-((m-1)*q) * m / 2 =
(n + n-((m-1)*(n/m)) * m / 2 ~ n * m / 2