使用expandAroundCenter函数的最长回文子字符串LeetCode解决方案,On ^ 3怎么不?

问题描述

那不是O(n ^ 3),因为在每个for循环中我们都做2个,而len1和len2都是一个循环吗?

以下解决方案正在正常输出回文。但是我很困惑。

这是LeetCode的解决方案:

public String longestpalindrome(String s) {
    if (s == null || s.length() < 1) return "";

    int start = 0,end = 0;
    //Loop 1
    for (int i = 0; i < s.length(); i++) {
        //Loop 2
        int len1 = expandAroundCenter(s,i,i);

        //Loop 3
        int len2 = expandAroundCenter(s,i + 1);
        int len = Math.max(len1,len2);
        if (len > end - start) {
            start = i - (len - 1) / 2;
            end = i + len / 2;
        }
    }
    return s.substring(start,end + 1);
}

private int expandAroundCenter(String s,int left,int right) {
    int L = left,R = right;
    while (L >= 0 && R < s.length() && s.charat(L) == s.charat(R)) {
        L--;
        R++;
    }
    return R - L - 1;
}

有什么主意吗?

解决方法

您可能对expandAroundCenter运行两次感到困惑。

expandAroundCenter函数为O(n)。它正在运行两次,但是按顺序运行。就像O(2n)而不是O(n ^ 2)。

并且在一个for循环中调用expandAroundCenter函数: T(n) = n x 2n = 2n^2 因此,时间复杂度为O(n ^ 2)。

,

争论很直接:

  • 外部循环为∈ O(n)
  • 两个内部循环(对expandAroundCenter(...)的调用)按顺序运行,而不是嵌套的。因此,它们的复杂性可以加起来
    • 对于内部循环,最坏的情况是它从String的中心向外扩展,即leftright设置为n/2。在这种情况下,自此之后,n/2left < 0之后,内部循环最多可以迭代right >= n次。因此,整个内部循环为∈ O(n)

总共,我们得到O(n) (outer loop) * 2 * O(n) (inner loops in sequence) ∈ O(n^2)


有关代码的一些说明:

  • 在可能的情况下,在Java中在一行中声明多个变量是不寻常的。因此

    int start = 0,end = 0;
    

    应该是

    int start = 0;
    int end = 0;
    

    此更改仅是代码样式选择,对字节码没有影响。有关详细信息,请参见this post

  • 不应省略单行语句周围的
  • 可选大括号。如果我们以后想要添加一行而忘记包括所需的花括号,则这可能是令人讨厌的错误的来源。因此

    if (s == null || s.length() < 1) return "";
    

    应重写为

    if (s == null || s.length() < 1) {
        return "";
    }
    
  • 变量名应始终以小写字母开头(L-> lR-> r)。

  • 变量应具有有意义的名称。 lr并不真正有意义。因此,我提出以下重构:

    • 将参数leftright重命名为leftStartrightStart
    • 将参数lr重命名为currentLeftcurrentRight