Longest Palindrome Substring (LeetCode) solution using expandAroundCenter function, how isn't O(n^3)?

huangapple go评论78阅读模式
英文:

Longest Palindrome Substring (LeetCode) solution using expandAroundCenter function, how isn't O(n^3)?

问题

代码部分不要翻译,只返回翻译好的内容:

如何不是O(n^3),因为在每个for循环内部,我们有两个while循环,一个用于len1,另一个用于len2?

下面的解决方案可以正确找到回文。但是我感到困惑。

这是来自LeetCode的解决方案:

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

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

        //循环3
        int len2 = expandAroundCenter(s, i, 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;
}

有什么想法吗?

英文:

How it's not O(n^3) since inside each for loop we do 2 while loops one for len1 and other for len2 ?

The below solution is working outputs the palindrome correctly. But I am confused.

Here is the solution from LeetCode:

public String longestPalindrome(String s) {
    if (s == null || s.length() &lt; 1) return &quot;&quot;;

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

        //Loop 3
        int len2 = expandAroundCenter(s, i, i + 1);
        int len = Math.max(len1, len2);
        if (len &gt; 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 &gt;= 0 &amp;&amp; R &lt; s.length() &amp;&amp; s.charAt(L) == s.charAt(R)) {
        L--;
        R++;
    }
    return R - L - 1;
}

Any idea ?

答案1

得分: 1

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

expandAroundCenter函数的时间复杂度是O(n)。虽然它被运行了两次,但是它是按顺序运行的。因此,时间复杂度是O(2n),而不是O(n^2)。

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

英文:

You might have got confused with expandAroundCenter running twice.

expandAroundCenter function is O(n). It is being run twice but, it is being run in sequence. So it is like O(2n) rather than O(n^2).

And as expandAroundCenter function is being called inside a for loop :
T(n) = n x 2n = 2n^2
So, time complexity is O(n^2).

答案2

得分: 0

以下是翻译好的内容:

参数的解释很直接:

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

总体而言,我们得到 O(n) (外部循环) * 2 * O(n) (按顺序运行的内部循环) ∈ O(n^2)


关于代码的一些备注:

  • 虽然可以,但在 Java 中一行中声明多个变量是不寻常的。因此

    int start = 0, end = 0;
    

    应改为

    int start = 0;
    int end = 0;
    

    此更改仅影响代码样式选择,不影响字节码。有关详细信息,请参见此帖子

  • 绝不能省略单行语句周围的可选大括号。如果以后想要添加一行并忘记包含所需的大括号,则可能会产生严重错误。因此

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

    应重新编写为

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

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

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

The argument is quite straight forward:

  • the outer loop is ∈ O(n)
  • the two inner loops (calls to expandAroundCenter(...)) run in sequence, not nested. Thus, their complexity can be added up
    • for the inner loop, the worst-case scenario is that it expands from the center of the String outwards, i.e. left and right are set to n/2. In this case, the inner loop can at most iterate n/2-times since then either left &lt; 0 or right &gt;= n. Thus, overall the inner loop is ∈ O(n)

In total, we get O(n) (outer loop) * 2 * O(n) (inner loops in sequence) ∈ O(n^2)


Some remarks on the code:

  • While possible, it is unusual in java to declare more than one variable in one line. Thus

    int start = 0, end = 0;
    

    should be

    int start = 0;
    int end = 0;
    

    This change is only code style choice and has no effect on byte code. See this post for details.

  • optional braces around one-line statements should never be omitted. This can be a source of nasty bugs if we later on want to add a line and forget to include the the needed braces. Thus

    if (s == null || s.length() &lt; 1) return &quot;&quot;;
    

    should be re-written to

    if (s == null || s.length() &lt; 1) {
        return &quot;&quot;;
    }
    
  • variable names should alwasy start with a lowercase letter (L -> l, R -> r).

  • variables should have meaningful names. l and r are not really meaningful. Thus I propose the following refactoring:

    • renaming parameters left and right to leftStart and rightStart
    • renaming parameters l and r to currentLeft and currentRight

huangapple
  • 本文由 发表于 2020年8月23日 06:34:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/63541753.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定