是这个代码的时间复杂度O(N ^ 2)

时间:2015-06-08 09:55:11

标签: java algorithm performance substring time-complexity

这是我的解决方案中的一个问题的解决方案。通过我的推论,我得出结论,它具有总体O(N ^ 2)时间复杂度。但是,我想对此进行确认,以便在判断算法的时间/空间复杂性时,我不会继续犯同样的错误。

哦,问题如下:

  

给定输入字符串,逐字反转字符串。   例如"我是你" =="你是我"

代码如下: -

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

我的理由是O(N ^ 2)算法: -

  1. 循环= O(n)
  2. StringBuilder.append = O(1)
  3. 子串方法= O(n)[从Java 7开始]
  4. 就此而言,如果其他人有更好的解决方案,请随时分享! :)

    我的目标是一次通过解决方案,因此选择在循环之前拆分字符串。

    感谢帮助!

    编辑:我想问一下包含循环的代码部分的时间复杂度。如果这个问题误导/混淆,我会提前道歉。整个代码块用于澄清目的。 :)

3 个答案:

答案 0 :(得分:5)

时间复杂度为O(n)

append(x)的每次插入(StringBuilder)都在O(|x|)完成,其中| x |}是要附加的输入字符串的大小。 (平均而言,与建造者的状态无关。)

您的算法会迭代整个字符串,并对其中的每个字词使用String#substring()。由于单词不重叠,这意味着您每次为每个单词执行substring(),并将其附加到构建器(也是一次) - 为每个单词2|x|提供x

总结一下,给你

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

但是从sum{|x| for each word x} <= |S|开始,这给你总计:

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

因为| S |是输入的大小(n),这是O(n)

请注意,重要的部分是在jdk7中,substring()方法在输出字符串的大小上是线性的,而不是原始的(您只复制相关部分,而不是所有字符串)。

答案 1 :(得分:1)

这是另一种解决方案,我认为可能会有所改善。

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

答案 2 :(得分:1)

Amit已经给你详细的复杂度计算解释,我想给你一个更简单的版本。

通常,如果我们有嵌套循环,我们认为复杂度为O(N ^ 2)。但事实并非如此,因为你必须为每个输入的第n部分做n次活动。例如,如果输入大小为3,则必须对每个元素执行3次操作。然后,您可以说您的算法具有O(n ^ 2)复杂度。

由于您只遍历和处理输入字符串的每个部分(即使您使用的是嵌套循环),因此复杂性应该是O(n)的顺序。为了证明,阿米特做了很多工作。

虽然,我会使用下面的代码来颠倒单词的顺序

String delim = " ";
String [] words = s.split(delim);
int wordCount = words.length; 

for(int i = 0; i < wordCount / 2; i++) {
    String temp = words[i];
    words[i] = words[wordCount - i - 1];
    words[wordCount - i - 1] = temp;
}

String result = Arrays.toString(words).replace(", ", delim).replaceAll("[\\[\\]]", "");