【问题标题】:I'm trying to understand how substring call is working in this code?我试图了解子字符串调用在这段代码中是如何工作的?
【发布时间】:2019-10-17 18:54:10
【问题描述】:

我知道子字符串是如何工作的,但我试图在下面的代码中理解它是如何工作的。目标是在字符串数组中找到最长的公共前缀。字符串输入是 {flower, flow,flece}。看起来 substring 只是取花的整个单词,当它不是 0 时,每次,因为 0 到 length-1 将给出整个单词。

 public String longestCommonPrefix(String[] strs) {
    if (strs.length == 0) return "";
    String prefix = strs[0];
    for (int i = 1; i < strs.length; i++)
        while (strs[i].indexOf(prefix) != 0) {
            prefix = prefix.substring(0, prefix.length() - 1);
            if (prefix.isEmpty()) return "";
        }        
    return prefix;
}

输出是 fl。我只是想了解原因。

【问题讨论】:

    标签: java substring indexof


    【解决方案1】:

    0 到 length-1 将给出整个单词


    不,它返回除最后一个字符之外的单词。
    来自:https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#substring(int,%20int)

    public String substring(int beginIndex, int endIndex)
    返回一个 作为此字符串的子字符串的新字符串。
    子字符串 从指定的 beginIndex 开始并延伸到字符 索引 endIndex - 1。

    所以代码所做的就是在每次迭代中用这一行修剪最后一个字符:

    prefix = prefix.substring(0, prefix.length() - 1);
    

    直到找到一个共同的前缀。

    【讨论】:

    • 我也对 while 条件感到困惑?如果它一直迭代到 0,它会一直迭代到单词的开头吗?当没有找到某些东西时,indexOf 返回负 1?
    • indexOf(prefix) != 0 的含义是前缀必须从与之比较的单词的第一个字符(索引=0)开始。所以循环继续修剪最后一个字符,直到前缀与单词的开头相同,这意味着它的起始位置是 0。
    【解决方案2】:

    substring() 中的 endIndex 是独占的。因此,代码所做的就是从前缀变量中删除最后一个字符。

    String hello = "hello";
    System.out.println(hello.substring(0,hello.length));
    // hello
    System.out.println(hello.substring(0,hello.length - 1));
    // hell
    

    【讨论】:

      【解决方案3】:

      虽然这不是您要直接询问的内容,但值得一提的是,使用 indexOfsubstring 并不是解决此问题的好方法。

      strs[i].indexOf(prefix) != 0 是一种检查字符串是否以某些内容开头的低效方法。这是因为如果它发现字符串不是以prefix 开头的,它会继续搜索其他位置的匹配项——它是否出现在那里并不重要。

      更有效的检查是!strs[i].startsWith(prefix):一旦发现字符串不是以前缀开头,它就会停止。

      那么,使用substring从字符串末尾截掉一个字符也是低效的:每次截掉一个字符时,它会创建一个新字符串,然后再检查一次;但是在找到匹配的前缀之前,您可能需要删除 很多 个单个字符。

      您可以通过使用strs[i].regionMatches(0, prefix, 0, someLength) 避免这种“创建对象”位,其中someLength 是一个从prefix.length() 开始的int,并且您递减直到regionMatches 返回true。但这仍然是低效的,因为您一次减少一个。

      如果换一种方式会更容易:从 someLength 零开始,然后递增直到:

      • 等于prefix的长度:someLength &gt;= prefix.length()
      • 等于strs[i]的长度:someLength &gt;= strs[i].length()
      • 该位置的对应字符不匹配:prefix.charAt(someLength) != strs[i].charAt(someLength)

      这基本上是startsWith 所做的,但通过“自己”做,您可以找出字符串不同的位置。

      然后,使用prefix = prefix.substring(0, someLength); 一口气砍掉它。或者根本不砍它:您可以简单地存储公共前缀的长度,并在最后执行一次子字符串。

      代码如下所示:

      public String longestCommonPrefix(String[] strs) {
          if (strs.length == 0) return "";
          int prefixLength = strs[0].length();
          for (int i = 1; i < strs.length; i++) {
              int s = 0;
              while (s < prefixLength
                  && s < strs[i].length()
                  && strs[0].charAt(s) == strs[i].charAt(s)) {
                ++s;
              }
              prefixLength = s;
          }
          return strs[0].substring(0, prefixLength);
      }
      

      【讨论】:

        猜你喜欢
        • 2021-07-03
        • 1970-01-01
        • 2018-02-07
        • 2019-04-20
        • 2016-05-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-16
        • 2014-05-10
        相关资源
        最近更新 更多