public static String findLongestSubstring(String str) {
for (int len = str.length(); len >= 2; len--) {
for (int i = 0; i <= str.length() - len; i++) {
String substr = str.substring(i, i + len);
int vowels = countVowels(substr);
int consonants = len - vowels;
if (vowels == consonants) {
return substr;
}
}
}
return "";
}
private static int countVowels(String str) {
return str.replaceAll("[^AEIOUaeiou]+", "").length();
}
自:problem
我的计算:
第一个循环有(str.length - 1)个旋转。第二个循环取决于第一个循环,所以它类似于:(0),[0,1],[0,1,2],...,[0,1 ...,str.length - 2]因此这是总共(仅第二循环)1 + 2 + ... + N - 2 =(2N-3)^ 2/8 -1 / 8~(2N)^ 2。如果我们让N = str.length。在第一个循环中,我们有(N-1)~N,因此总共~N ^ 3。但是我们必须假设在两个循环中,它是O(1)否则我们有&gt; O(N ^ 3)?
但我不认为这是对的。
我们如何计算这样的时间复杂度?
答案 0 :(得分:2)
如果n
是str
的长度。
外部循环可以近似(正如您所做) O(n)
。
内环也可以近似为 O(n),因为{{1}时它从最少的0个循环变为最大的n个循环}是0。
因此,如果您不考虑length
和substring
方法内部发生的情况,复杂性 O(n)* O( n) - &gt;的为O(n ^ 2)。强>
请注意replaceAll
遍历整个字符串,因此其内部复杂度为O(n)。考虑到这一点,复杂性是O(n ^ 3)。
答案 1 :(得分:2)
假设n
的长度为str
,您会得到:
n - 1
次: O(n) n - 1
次,因此平均n / 2
次: O(n) replaceAll()
在countVowels()
内迭代2到n
个字符,因此平均n / 2 + 1
次: O(n)
注意: substring()
的效果取决于version of Java,因此它是 O(1)(早期Java)或 O(n)(后来的Java)。但是因为 O(1) + O(n)和 O(n) + O(n)是两个 O(n),它对内部循环体的性能没有影响,这就是为什么上述逻辑只考虑replaceAll()
的性能。
<强>更新强>
计算外循环和内循环的性能有三种方法,不包括正文中的内容:
O 数学:外环是 O(n),内环是 O(n),所以总数是 O(n) * O(n) = O(n 2 )
迭代数学:外循环迭代n - 1
次,内循环迭代n / 2
次(平均),因此总计为(n - 1) * (n / 2) = n² / 2 - n / 2
。由于只有增长最快的因子计数,这意味着 O(n 2 )
迭代和:对内循环的迭代求和,即1 + 2 + ... + n-1
。序列的总和可以计算为count * average
,平均值可以计算为(min + max) / 2
。这意味着average = (1 + n-1) / 2 = n / 2
和sum = (n - 1) * (n / 2)
,这与我们在上面#2中获得的结果完全相同,因此它是 O(n 2 )
正如您所看到的, O 数学更简单,因此这就是为什么选择答案的原因。