简体   繁体   中英

Calculate the time complexity of this specific algorithm

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(); 
 }

From: problem

MY CALCULATION:

The first loop has (str.length - 1) rotations. The second loop depends on the first loop, so it goes like: (0), [0, 1], [0, 1, 2] , ... , [0, 1 .., str.length - 2] Thus this is a total of (Second loop only) 1 + 2 + ... + N - 2 = (2N-3)^2/8 -1/8 ~ (2N)^2. If we let N=str.length. In the first loop, we have (N-1) ~ N, thus a total of ~N^3. But then we have to assume that inside both the loops, it is O(1) otherwise we have have > O(N^3)?

But I don't think this is right.

How do we calculate such a time complexity?

If n is the length of str .

The external loop can be approximated (as you did) to O(n) .

The inner loop can be approximated to O(n) too, because it goes from a minimum of 0 cycles to a maximum of n cyles when length is 0.

So if you DON'T consider what happens internally in substring and replaceAll methods the complexity is O(n) * O(n) -> O(n^2).


Note that the replaceAll iterate over the whole string, so his internal complexity is O(n). Considering also this the complexity is O(n^3).

Assuming n is length of str , you get:

  • Outer loop iterates n - 1 times: O(n)
  • Inner loop iterates 1 to n - 1 times, so on average n / 2 times: O(n)
  • replaceAll() inside countVowels() iterates over 2 to n characters, so on average n / 2 + 1 times: O(n)
  • Total is O(n) * O(n) * O(n) , so: O(n 3 )

Note: Performance of substring() depends on version of Java , so it is either O(1) (earlier Java) or O(n) (later Java). But since O(1) + O(n) and O(n) + O(n) is both O(n) , it makes no difference for performance of inner loop body, which is why the above logic only considers the performance of replaceAll() .


UPDATE

There are three ways of calculating performance for outer and inner loop combined, excluding what happens in the body:

  1. O math: Outer loop is O(n) , and inner loop is O(n) , so total is O(n) * O(n) = O(n 2 )

  2. Iteration math: Outer loop iterates n - 1 times, and inner loop iterates n / 2 times (on average) , so total is (n - 1) * (n / 2) = n² / 2 - n / 2 . Since only fastest growing factor counts, that means O(n 2 )

  3. Iteration sum: Sum the iterations of inner loop, ie 1 + 2 + ... + n-1 . Sum of a sequence can be calculated as count * average , and average can be calculated as (min + max) / 2 . That means that average = (1 + n-1) / 2 = n / 2 , and sum = (n - 1) * (n / 2) , which is exactly the same result we got in #2 above, so it is O(n 2 )

As you can see, O math was simpler, so that's why it was chosen for the answer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM