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:-
- The loop = O(n)
- StringBuilder.append = O(1)
- 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. :)
Time complexity is
O(n)
.Each insertion (
append(x)
) to aStringBuilder
is done inO(|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 asubstring()
for each word one time, and append it to the builder (also once) - giving you2|x|
for each wordx
.Summing it up, gives you
But since
sum{|x| for each word x} <= |S|
, this gives you total of:Since |S| is the size of the input (
n
), this isO(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).