如何使用Java SReam找到最长的重复子弦?

发布于 2025-02-10 10:21:06 字数 1739 浏览 1 评论 0原文

对于学校作业,我必须实现一种方法,该方法将从字符串中返回最长的重复子字符串。但是我必须仅使用流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

所以我想知道是否可能吗?我还尝试使用三个参数使用redy(),但它也不起作用,我可以在流外部使用一个变量来跟踪和更改“ braderedredendansubstring”的值可变,但这违背了为什么使用流,不是吗?

For a school assignment, I have to implement a method that will return the longest repeated substring from a string. But I have to do it by using only the Stream API.

This is what I have done so far:

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;
            });
}

And this is the main() method:

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));
    }
}

This without arguments should print on console:

ababaac aba

But instead it prints:

ababaac ababaac

So I was wondering if it is possible? I also tried to use reduce() with three parameters, but it doesn't work either, and I could use a variable outside of the stream to keep track of and change the value of the "biggestRedundantSubstring" variable, but it kind of goes against why to use streams, doesn't it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

刘备忘录 2025-02-17 10:21:06

首先,让我们描述总体算法

  • 我们需要生成所有可能的 substring 。 IE对于0str.length() - 1的字符串的每个有效索引1 to str.length() - 索引

  • 然后,我们需要检查以下 substring 不止一次出现并选择最长的子字符串。

要生成所有子字符串,我们需要使用Nested intstream浏览所有有效的索引(可以使用循环的嵌套进行相同的操作)。当我们拥有所有可能的开始结束索引时,我们可以将它们变成 substrings

然后,为了找出这些子字符串不止一次出现,我们可以使用映射map&lt; string,boolean&gt;,其中将是字符串本身和a < em> value 映射到每个将表示是否重复。我们可以使用 collector “ nofollow noreferrer”>

然后,当我们需要在辅助地图的条目上创建流时。滤除重复的条目,然后使用max()操作选择具有最高长度的条目,该操作返回可选对象并期望比较器作为参数。

这就是外观:

public static String biggestRedundantSubstring(String str) {
    
    return IntStream.range(0, str.length()) // generating starting indices
        .boxed()
        .flatMap(start -> IntStream.rangeClosed(start + 1, str.length()).mapToObj(end -> str.substring(start,  end))) // generating ending indices and turning each combination of `start` and `end` into a substring
        .collect(Collectors.toMap(   // creating an intermediate map Map<String, Boolean>
            Function.identity(),
            s -> false,              // is repeated substring = false, because element has been encountered for the first time
            (v1, v2) -> true         // substring has been encountered more than once, i.e. is proved to be repeated
        ))
        .entrySet().stream()
        .filter(Map.Entry::getValue) // filtering the repeated substrings
        .max(Map.Entry.comparingByKey(Comparator.comparingInt(String::length))) // returns Optional<Map.Entry<String, Boolean>>
        .map(Map.Entry::getKey)      // returns Optional<String>
        .orElse("");                 // if Optional is empty return an empty string
}

main()

public static void main(String[] args) {
    String s = "ababaac";
    System.out.println(s + " " + biggestRedundantSubstring(s));
}

输出:

ababaac aba

Firstly, let's describe the overall algorithm:

  • We need to generate all possible substrings. I.e. for every valid index of the string from 0 up to str.length() - 1 we have to construct all substrings having the length from 1 to str.length() - index.

  • Then we need to check which of these substrings occur more than once and pick the longest of them.

To generate all substring, we need to walk through all the valid indices using nested IntStream (the same can be done using a nested for loop). And when we have all the possible starting and ending indices, we can turn them into substrings.

Then to find out which of these substrings appear more than once, we can use a map Map<String,Boolean>, in which keys would be the strings itself and a value mapped to each key would signify whether it's repeated or not. We can do this by using collector toMap(keyMapper,valueMapper,mergeFunction).

Then when we need to create a stream over the entries of the auxiliary map. Filter out repeated entries and pick the one that has the highest length by using max() operation that returns an Optional object and expects a Comparator as an argument.

That's how it might look like:

public static String biggestRedundantSubstring(String str) {
    
    return IntStream.range(0, str.length()) // generating starting indices
        .boxed()
        .flatMap(start -> IntStream.rangeClosed(start + 1, str.length()).mapToObj(end -> str.substring(start,  end))) // generating ending indices and turning each combination of `start` and `end` into a substring
        .collect(Collectors.toMap(   // creating an intermediate map Map<String, Boolean>
            Function.identity(),
            s -> false,              // is repeated substring = false, because element has been encountered for the first time
            (v1, v2) -> true         // substring has been encountered more than once, i.e. is proved to be repeated
        ))
        .entrySet().stream()
        .filter(Map.Entry::getValue) // filtering the repeated substrings
        .max(Map.Entry.comparingByKey(Comparator.comparingInt(String::length))) // returns Optional<Map.Entry<String, Boolean>>
        .map(Map.Entry::getKey)      // returns Optional<String>
        .orElse("");                 // if Optional is empty return an empty string
}

main()

public static void main(String[] args) {
    String s = "ababaac";
    System.out.println(s + " " + biggestRedundantSubstring(s));
}

Output:

ababaac aba
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文