Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is the time complexity of this code O(N^2)

This is a solution of mine for one of the problems in leetcode. Through my deductions, I concluded it to have an overall O(N^2) time complexity. However, I would like to get a confirmation on this just so that I don't continue making the same mistakes when it comes to judging the time/space complexity of an algorithm.

Oh, and the problem goes as follows:

Given an input string, reverse the string word by word. e.g. "I am you" == "you am I"

The code is as follows:-

public String reverseWords(String s) {
        //This solution is in assumption that I am restricted to a one-pass algorithm.
        //This can also be done through a two-pass algorithm -- i.e. split the string and etc.

        if(null == s)
            return "";
        //remove leading and trailing spaces
        s = s.trim();
        int lengthOfString = s.length();
        StringBuilder sb = new StringBuilder();
        //Keeps track of the number of characters that have passed.
        int passedChars = 0;
        int i = lengthOfString-1;
        for(; i >= 0; i--){
            if(s.charAt(i) == ' '){
                //Appends the startOfWord and endOfWord according to passedChars.
                sb.append(s.substring(i+1, (i+1+passedChars))).append(" ");
                //Ignore additional space chars.
                while(s.charAt(i-1) == ' '){
                    i--;
                }
                passedChars = 0;
            }else{
                passedChars++;
            }
        }

        //Handle last reversed word that have been left out.
        sb.append(s.substring(i+1, (i+1+passedChars)));

        //return reversedString;
        return sb.toString();
    }

My reasoning for this being an O(N^2) algorithm:-

  1. The loop = O(n)
  2. StringBuilder.append = O(1)
  3. Substring method = O(n) [as of Java 7]

On that note, if anyone else has a better solution than this, please feel free to share it! :)

I was aiming for a one-pass solution and therefore, opted out of splitting the string before the loop.

Appreciate the help!

EDIT: I meant to ask about the time complexity of the portion of the code that contains the loop. I apologize in advance if the question was misleading/confusing. The whole chunk of code is meant for clarification purposes. :)

like image 632
cottonman Avatar asked Mar 15 '23 19:03

cottonman


2 Answers

Time complexity is O(n).

Each insertion (append(x)) to a StringBuilder is done in O(|x|), where |x| is the size of the input string you are appending. (independent of the state of the builder, on average).

Your algorithm iterates the entire string, and use String#substring() for each word in it. Since the words do not overlap, it means you do a substring() for each word one time, and append it to the builder (also once) - giving you 2|x| for each word x.

Summing it up, gives you

T(S) = |S| + sum{2|x| for each word x}

But since sum{|x| for each word x} <= |S|, this gives you total of:

T(S) = |S| + 2sum{|x| for each word x} = |S| + 2|S| = 3|S|

Since |S| is the size of the input (n), this is O(n)


Note that the important part is in jdk7, the substring() method is linear in the size of the output string, not the original one (you copy only the relevant part, not all of the string).

like image 137
amit Avatar answered Mar 23 '23 02:03

amit


Here is an alternative solution which I believe may perform a little better.

public String reverseWords(String s) {
    String[] array = s.split(" ");
    int len = array.length;

    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < len; i++) {
        sb.append(" ").append(array[len - i - 1]);
    }

    return sb.toString().trim();
}
like image 36
pnadczuk Avatar answered Mar 23 '23 02:03

pnadczuk