【问题标题】:Common Substring of two strings两个字符串的公共子串
【发布时间】:2023-03-29 02:57:01
【问题描述】:

这个特别的面试问题难倒我:

Given two Strings S1 and S2. Find the longest Substring which is a Prefix of S1 and suffix of S2

通过谷歌,我遇到了以下解决方案,但不太明白它在做什么。

public String findLongestSubstring(String s1, String s2) {
        List<Integer> occurs = new ArrayList<>();
        for (int i = 0; i < s1.length(); i++) {
            if (s1.charAt(i) == s2.charAt(s2.length()-1)) {
                occurs.add(i);
            }
        }

        Collections.reverse(occurs);

        for(int index : occurs) {
            boolean equals = true;
            for(int i = index; i >= 0; i--) {
                if (s1.charAt(index-i) != s2.charAt(s2.length() - i - 1)) {
                    equals = false;
                    break;
                }
            }
            if(equals) {
                return s1.substring(0,index+1);
            }
        }

        return null;
    }

我的问题:

  1. 此解决方案如何工作?
    • 您是如何发现这个解决方案的?
  2. 有更直观/更简单的解决方案吗?

【问题讨论】:

  • 做电脑。你有一个你理解的问题,以及一个回答它的程序,但你不理解。所以要做的就是在纸上画一个例子,一步一步地运行。一段时间后,您要么会理解算法在做什么,要么会想到更好的算法。但它绝对必须在实践中完成,有一个具体的例子,并且可能以书面形式进行 - 在你的头脑中进行这种分析更难,并且需要更多的算法经验。
  • @KilianFoth 我已经试过了。对不起,我没有在问题中提到这一点。我面临的问题是,虽然解决方案有效,但我无法直观地理解它为什么有效,以及人们是如何得出这个解决方案的。因此,我一直在寻找一个直观的解释,说明如何获得这个解决方案,或者我更容易理解的其他解决方案。
  • 我用 3 行 java 代码 here 实现了一个解决方案。正如@Kilian 所写,您应该首先尝试自己找到解决方案,因为您将从中获得更多收益。即使您可能犯的错误将来也会有用。 ;) 您发布的代码实现了我在代码中省略的一些优化。
  • 查看我的答案以获得更深入的描述和对您发布的代码的解释。

标签: java algorithm


【解决方案1】:

您问题的第 2 部分

这是一个较短的变体:

public String findLongestPrefixSuffix(String s1, String s2) {

   for( int i = Math.min(s1.length(), s2.length()); ; i--) {
      if(s2.endsWith(s1.substring(0, i))) {
         return s1.substring(0, i);
      }
   }    
}

我正在使用Math.min 来查找最短字符串的长度,因为我不需要也无法进行更多比较。

someString.substring(x,y) 返回从字符 x 开始读取 someString 并在字符 y 处停止时获得的字符串。我从可能的最大子字符串(s1s2)倒退到可能的最小子字符串,即空字符串。这样,当我的条件第一次为真时,它将是最大可能的子字符串。

如果你愿意,你可以反过来,但你必须引入一个变量来保存迄今为止满足条件的最长找到的子字符串的长度:

public static String findLongestPrefixSuffix(String s1, String s2) {

   if (s1.equals(s2)) { // this part is optional and will 
      return s1;        // speed things up if s1 is equal to s2
   }                    //

   int max = 0;
   for (int i = 0; i < Math.min(s1.length(), s2.length()); i++) {
      if (s2.endsWith(s1.substring(0, i))) {
         max = i;
      }
   }
   return s1.substring(0, max);
}

郑重声明:您可以在后一个示例中以 i = 1 开头,以获得一点点额外性能。最重要的是,您可以使用i 指定后缀至少需要多长时间。 ;) 如果你写了Math.min(s1.length(), s2.length()) - x,你可以使用x 来指定找到的子字符串最多可以有多长。第一种解决方案也可以实现这两件事,但是最小长度涉及更多。 ;)


您问题的第 1 部分

Collections.reverse上方的部分,代码作者搜索s1s2的最后一个字母所在的所有位置并保存该位置。

接下来的内容基本上是我的算法所做的,不同之处在于,他不会检查每个子字符串,而只会检查以s2 最后一个字母结尾的子字符串。

这是一种加快速度的优化。如果速度不是那么重要,我的幼稚实现就足够了。 ;)

【讨论】:

  • 感谢@TheMorph 提供如此详细的解释!
  • 也许应该将 s1.substring(0, i) 保存在一个变量中并重复使用它而不是调用它两次。
【解决方案2】:

您在哪里找到了该解决方案?它是由可信的、受人尊敬的程序员编写的吗?如果您不确定这一点,那么它可能不值得阅读。人们可以编写非常复杂且效率低下的代码来完成非常简单的事情,并且不值得理解算法。

与其试图理解别人的解决方案,不如自己想出解决方案更容易。我认为这样你会更好地理解问题,逻辑就变成了你自己的。随着时间的推移和练习,思维过程将开始变得更加自然。熟能生巧。

无论如何,我在 Python here 中放置了一个更简单的实现(剧透警告!)。我建议你先自己找出解决方案,然后再与我的比较。

【讨论】:

  • 我写了一个更短的small implementation in java(总共 3 个 LOC),更直观的恕我直言,然后是 OPs 代码。另一方面,我们的 OP 代码缺少一些优化。还没有测试过,但是我的代码在大字符串上可能会很慢,对你来说也是如此。但我认为我们的代码很好地传达了对问题的基本理解。
【解决方案3】:

Apache commons lang3,StringUtils.getCommonPrefix()

Java 在通过 stdlib 提供有用的东西方面确实很糟糕。从好的方面来说,Apache 几乎总是有一些合理的工具。

【讨论】:

    【解决方案4】:

    我将@TheMorph 的答案转换为javascript。希望这对 js 开发者有所帮助

    if (typeof String.prototype.endsWith !== 'function') {
        String.prototype.endsWith = function(suffix) {
            return this.indexOf(suffix, this.length - suffix.length) !== -1;
        };
    }
    
    function findLongestPrefixSuffix(s2, s1) {
    
       for( var i = Math.min(s1.length, s2.length); ; i--) {
          if(s2.endsWith(s1.substring(0, i))) {
             return s1.substring(0, i);
          }
       }    
    }
    
    console.log(findLongestPrefixSuffix('abc', 'bcd')); // result: 'bc'
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-20
      相关资源
      最近更新 更多