【问题标题】:Find longest substring formed with characters of other string查找由其他字符串的字符组成的最长子字符串
【发布时间】:2013-12-03 07:22:47
【问题描述】:

给定两个字符串:

str1 = "abcdefacbccbagfacbacer"
str2 = "abc"

我必须在str1 中找到由str2 的字符子集形成的最长子字符串,在本例中为-7 (acbccba)。以最小的复杂性解决这个问题的方法是什么。首先我想到了DP。但是,我猜这真的不需要 DP,因为我们必须搜索子字符串,而不是子序列。然后我想到了后缀树。但这需要额外的预处理时间。

最好的方法是什么?事实上,这个问题甚至适用于后缀树或 DP 吗?

【问题讨论】:

  • 您的意思是包含来自str2 的(某些子集)字符的任何排列的子字符串吗?
  • @ElliottFrisch 是的,str2 的任何字符。
  • @Elliott Frisch - 尽管是的,但这对我来说似乎是不。示例最长的结果是“acbccba”,这显然不是来自“abc”的字符子集的排列 - 它重复了所有这些字符。在我看来,“abc”只是一组可以出现的字符。
  • @Steve314 实际上它不必包含来自abc 的所有字符。例如,如果有一个子字符串 - ababababab,那么这就是一个答案。很抱歉这个误导性的例子。
  • @user3011937 - 理解 - “可以发生”并不意味着“必须发生”。我认为您误解的是排列是(可能)以不同顺序(不重复)中的相同项目。 “acbccba”不是“abc”的排列,因为您不能简单地通过重新排序“abc”中的项目来获得“acbccba”。 “cba”是“abc”的排列,“aabbccc”是“acbccba”的排列。

标签: java string algorithm optimization complexity-theory


【解决方案1】:

迄今为止最简单的方法:

  1. 构建第二个字符串的哈希集。
  2. 遍历第一个字符串并检查每个字符是否在哈希集中。跟踪最长的子字符串。

运行时间:O(n+m) 其中nstr1 的长度,mstr2 的长度。


(未经测试)代码:

Set<Character> set = new HashSet<>();
for (int i = 0; i < str2.length(); i++) {
    set.add(str2.charAt(i));
}

int longest = 0;
int current = 0;
int longestEnd = -1;
for (int i = 0; i < str1.length(); i++) {
    if (set.contains(str1.charAt(i)) {
        current++;
        if (current > longest) {
            longest = current;
            longestEnd = i + 1;
        }
    } else {
        current = 0;
    }
}

String result = "";
if (longest > 0) {
    result = str1.substr(longestEnd - longest, longestEnd);
}

【讨论】:

  • 你可以停止@n-(迄今为止发现的最长)。
【解决方案2】:

只是一个想法:将第二个字符串包装在 [] 中并使用 Pattern 的匹配方法:

Pattern p = Pattern.compile("(["+str2+"])");
Matcher m = p.matcher(str1);
m.find();

然后 m.group(1) 会找到它。

【讨论】:

  • 我在这里尽量避免使用正则表达式,因为效率是一个问题。这无论如何都是O(|str1|) 算法,加上正则表达式模式处理的额外开销。最好将其视为一般算法问题。
  • 你怎么能确定m.group(1) 是最长的?
  • 请在上面加上Pattern.quote,去掉外面的(),改用group(0),但是你不会找到最长的,只有第一个——你需要找到所有他们并跟踪最长的一个。
【解决方案3】:

其实我能想到的方法只有一种:

  1. 继续字符串 str1 的字符。
  2. foreach char 在 str1 检查它是否在 str2
  3. 每次在 str2 中找到 str1 中的当前字符时,增加一个计数器 (i)
  4. 一旦 str1 中不属于 str2 的字符保存计数器 (i) 值(如果它比 maxfound 中的 maxfound 计数器(代表最长找到的序列)更早)并重置 (i) 计数器。

【讨论】:

    【解决方案4】:

    在 Perl 中测试的代码。

        use strict;
        use warnings;
    
        my $str1 = "abcdefacbccbagfacbacer";
        my $str2 = "abc";
    
        my @str1 = split ("", $str1);
        my @str2 = split ("", $str2);
    
        my @res = ();
        my $index = undef;
        my $max = 0;
        my @max_char = ();
    
        for(my $i = 0; $i < @str1; $i++){
    
            if ($str1[$i] =~ /[@str2]/){
                push (@res , $str1[$i]);
                next;
            }else{
                if(@res > $max){
                    $max = @res;
                    @max_char = @res;
                    $index = $i;
                }
                @res = ();
            }
        }
        if(@res > $max){
            @max_char = @res;
            $index = $i;
        }
    
        $index = $index - $#max_char - 1;
        print "Longest substring = @max_char.  Starting from index $index";
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-04-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-05
      • 1970-01-01
      相关资源
      最近更新 更多