You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Java Stream正确实现最长重复子串查找并修复代码错误

问题描述

在完成课程作业时,我需要实现一个方法,用于返回给定字符串中的最长重复子串,且要求仅使用Stream API完成该功能。

以下是我目前编写的核心方法代码:

public static String biggestRedundantSubstring(String s) {
    Stream.Builder<String> stringBuilder = Stream.builder();
    while (!Objects.equals(s, "")) {
        stringBuilder.add(s);
        s = s.substring(1);
    }
    return stringBuilder.build().sorted().reduce("",
            (String biggestRedundantSubstring, String matchingPrefix) ->
                    biggestRedundantSubstring.length() > matchingPrefix.length() ?
                            biggestRedundantSubstring : matchingPrefix,
            (String sub1, String sub2) -> {
                String matchingPrefix = "";
                int limitIndex = Math.max(sub1.length(), sub2.length()) - 1;
                for (int i = 0; i < limitIndex; i++) {
                    if (sub1.charAt(i) == sub2.charAt(i)) {
                        matchingPrefix += sub1.charAt(i);
                    } else {
                        break;
                    }
                }       
                return matchingPrefix;
            });
}

对应的main()方法代码如下:

public static void main(String[] args) {
    if (args.length != 0) {
        for (String s : args) {
            System.out.println(s + " " + biggestRedundantSubstring(s));
        }
    } else {
        String s = "ababaac";
        System.out.println(s + " " + biggestRedundantSubstring(s));
    }
}

运行现象:

  • 无参数运行该程序时,预期控制台输出为:
ababaac aba
  • 实际运行输出为:
ababaac ababaac

待确认问题:

  • 仅使用Stream API实现该需求是否可行?
  • 此前尝试使用三参数的reduce()方法但依然无法得到正确结果;也考虑过在流外部定义变量来追踪更新最长重复子串的值,但这种写法违背了Stream的设计使用初衷,并不合适。现有代码存在什么问题,该如何修正?

解答

完全使用Stream API实现该需求是可行的,现有代码的问题集中在对Stream API执行逻辑的理解偏差,以及算法落地的细节错误,具体如下:

现有代码核心错误

  1. 三参数reduce()方法使用错误:该重载方法的第三个combiner函数,仅在并行流场景下才会被调用,用于合并多个分片的计算结果。你当前构建的是串行流,写在combiner里的公共前缀计算逻辑根本不会触发,实际生效的accumulator逻辑只会单纯比较字符串长度,返回流中最长的元素也就是原串本身,这就是输出错误的根本原因。
  2. 公共前缀计算边界错误:你用Math.max(sub1.length(), sub2.length()) - 1作为循环上限,当两个字符串长度不相等时,会触发StringIndexOutOfBoundsException,正确的循环上限应该取两个字符串长度的最小值。
  3. 算法逻辑缺失:你选择的「生成所有后缀+字典序排序+相邻后缀求最长公共前缀」是最长重复子串的经典实现思路,但你没有实现「相邻后缀两两比对」的核心步骤,直接把所有后缀丢进reduce()无法获取元素的相邻关系,自然算不出正确结果。

修正后实现

以下实现完全基于Stream API,没有使用流外的可变状态追踪结果,符合Stream的函数式设计规范,可直接运行得到预期结果:

import java.util.Objects;
import java.util.stream.IntStream;

public class LrsSolver {
    public static String biggestRedundantSubstring(String s) {
        if (Objects.isNull(s) || s.length() < 2) {
            return "";
        }
        // 生成所有后缀并按字典序排序
        String[] sortedSuffixes = IntStream.range(0, s.length())
                .mapToObj(s::substring)
                .sorted()
                .toArray(String[]::new);

        // 相邻后缀两两计算公共前缀,取最长的结果
        return IntStream.range(0, sortedSuffixes.length - 1)
                .mapToObj(i -> {
                    String pre = sortedSuffixes[i];
                    String next = sortedSuffixes[i+1];
                    int minLen = Math.min(pre.length(), next.length());
                    int prefixLen = 0;
                    while (prefixLen < minLen && pre.charAt(prefixLen) == next.charAt(prefixLen)) {
                        prefixLen++;
                    }
                    return pre.substring(0, prefixLen);
                })
                .max((a, b) -> a.length() - b.length())
                .orElse("");
    }

    public static void main(String[] args) {
        if (args.length != 0) {
            for (String s : args) {
                System.out.println(s + " " + biggestRedundantSubstring(s));
            }
        } else {
            String s = "ababaac";
            System.out.println(s + " " + biggestRedundantSubstring(s));
        }
    }
}

运行无参数main方法,会正确输出ababaac aba,和预期一致。

补充说明

  • 不要强行用三参数reduce()承载串行流的业务逻辑,它的设计目标是服务并行流的结果合并,串行流场景下不会触发combiner逻辑,硬写逻辑只会静默失效。
  • 如果需要更简洁的链式写法,可以把公共前缀计算抽成独立工具函数,不会违反Stream的使用规范。

内容的提问来源于stack exchange,提问作者Mr.D

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 06:18:09