【问题标题】:Big-O analysis of a sub-string of string algorithm. Does O(n*logn) simplify?Big-O 分析字符串算法的子字符串。 O(n*logn) 是否简化?
【发布时间】:2013-01-30 22:40:02
【问题描述】:

您好,感谢您的阅读。我正在做家庭作业。我创建了一种与字符串进行比较的方法,以查看一个是否是另一个的子字符串。我知道已经有一个内置的方法可以做到这一点。作业不允许我使用它们。无论如何,下面的代码是有效的。

我必须使用 Big-O 表示法来分析算法的复杂性。从我所见,外循环以线性时间运行,因为它运行的次数与字符串的长度一样多。因此:O(n)

内部循环是不同的,它可能会发生也可能不会发生,如果发生了,它可能会在它输入的第二个字符串的长度之前完成。因此:O(logn)

所以在我看来复杂度是 O (n*logn)。这会简化为 O(n) 还是保持当前形式?或者我错了内循环是 O(logn)?

import java.util.Scanner;

public class HW3q6 {
public static void main(String[] args) {
    Scanner userInput = new Scanner( System.in );
    System.out.println("Please enter the first string: ");
    char[] charArray1 = userInput.nextLine().toUpperCase().toCharArray();
    System.out.println("Please enter the second string: ");
    char[] charArray2 = userInput.nextLine().toUpperCase().toCharArray();

    System.out.println("The second string is a substring of the first: " + subString(charArray1, charArray2));

}

private static boolean subString(char[] charArray1, char[] charArray2) {
    int counter = 0;
    for (int i = 0; i < (charArray1.length + 1) - charArray2.length ; i++) {
        if (charArray1[i] == charArray2[0]) {
            for (int n = 0; n < charArray2.length; n++) {
                if (charArray1[i+n] == charArray2[n]) {
                    counter++;
                }
            }
            if (counter == charArray2.length) {
                return true;
            } else
                counter = 0;
        }
    }
    return false;

}
}

【问题讨论】:

  • 如果一个循环可能提前退出,它仍然是O(n)。它不会变成O(log n)。复杂性O(log n) 专门指将集合大小重复减小某个因素,即搜索二叉树,或在排序数组中进行二分搜索。
  • 啊,因为我们正在考虑最坏的情况,对吧?来自用户的第二个输入可能和第一个一样长,因此它被认为与 n 一样大。
  • 是的,它是关于可证明的上限。即使您知道在实践中每次迭代的内部循环运行次数可能远少于n 次,但您通常只能证明它在最坏的情况下是n
  • wlog,假设字符串长度为 m,n 和 m
  • 感谢您的所有回答。它似乎是 O(n^2) 但是我仍然有一个犹豫。如果用户输入与第一个字符串一样长的第二个字符串(要比较的子字符串),则外部循环将只运行一次。如果用户不输入任何内容,则内部循环根本不会运行。编辑:我看到这意味着 O(mn) 是答案。这是有道理的,但教科书中没有 m*n 的例子。 Edit2:Rivu 指出这简化为 O(n^2)

标签: java algorithm data-structures big-o


【解决方案1】:

内循环不是logN。 Big O 衡量最坏情况的复杂性。正如我从您的代码中了解到的那样,内部循环可以运行 N(字符串长度 2)次。解释如下:

假设你有两个字符串 aaaaaaaa 和 aaac,外循环将匹配第一个字符,你将进入内循环,检查每个字符,然后实现一个 false。然后外循环将再次将第二个字符串的开头与第一个字符串的第二个字符匹配,然后您将再次检查第二个字符串中的所有字符是否为假。这将适用于第一个字符串的 M 个字符,以及第二个字符串的 N 个字符,产生一个 O(MN) 算法,考虑到 M=c*N,它是 O(N^2),其中 c 是一个常数。

希望这会有所帮助。

【讨论】:

  • which is O(N^2) considering M=c*N where c is a constant. 伙计,你是怎么想出这些东西的?那么为什么不考虑O(N^3) M=c*N where c=N。你从哪里得到这个c?光速? :)
【解决方案2】:

我看到你已经接受了一个答案。但是您的时间复杂度实际上是O(m*(n-m+1)),其中m 是较小的文本,n 是较大的文本。要看到这种区别很重要,只需为 m 和 n 选择几个数字并计算。如果论点是当涉及到 Big-O 表示法时,O(mn)O(m*(n-m+1)) 之间没有太大区别,因为O(mn) &gt; O(m*(n-m+1)),那么你可以说复杂度是O(n^2),因为O(n^2) &gt; O(mn) &gt; O(m*(n-m+1))。此外,您的代码没有进行正确的错误检查,请参阅Geekviewpoint.com on string matching for some hints.

【讨论】:

    【解决方案3】:

    O(NlogN) 不等同于O(N)

    但是,您认为内部循环是 O(logN) 的推理是错误的。它“可能发生也可能不会发生”的事实并不一定使它成为O(logN)。例如,如果内部循环发生“平均大约一半的时间”,那么贡献很可能是C * 1/2 N;即O(N)

    我现在没有时间详细分析代码,但您似乎需要查看最佳、平均和最差情况的复杂性。

    (例如,快速排序算法的经典形式,平均为O(NlogN),但最坏情况复杂度为O(N^2)。)

    【讨论】:

      【解决方案4】:

      正如 mellamokb 指出的那样,内部循环仍然以线性时间运行。因此,您的算法作为一个整体将是 O(mn),其中 m 和 n 是两个字符串的长度。

      【讨论】:

        猜你喜欢
        • 2023-03-25
        • 1970-01-01
        • 2022-10-13
        • 1970-01-01
        • 2020-05-13
        • 1970-01-01
        • 2017-04-03
        • 2016-02-16
        • 2017-02-05
        相关资源
        最近更新 更多