leetcode
leetcode 2351 ~ 2400
包含三个字符串的最短字符串

包含三个字符串的最短字符串

难度:

标签:

题目描述

Given three strings a, b, and c, your task is to find a string that has the minimum length and contains all three strings as substrings.

If there are multiple such strings, return the lexicographically smallest one.

Return a string denoting the answer to the problem.

Notes

  • A string a is lexicographically smaller than a string b (of the same length) if in the first position where a and b differ, string a has a letter that appears earlier in the alphabet than the corresponding letter in b.
  • A substring is a contiguous sequence of characters within a string.

 

Example 1:

Input: a = "abc", b = "bca", c = "aaa"
Output: "aaabca"
Explanation:  We show that "aaabca" contains all the given strings: a = ans[2...4], b = ans[3..5], c = ans[0..2]. It can be shown that the length of the resulting string would be at least 6 and "aaabca" is the lexicographically smallest one.

Example 2:

Input: a = "ab", b = "ba", c = "aba"
Output: "aba"
Explanation: We show that the string "aba" contains all the given strings: a = ans[0..1], b = ans[1..2], c = ans[0..2]. Since the length of c is 3, the length of the resulting string would be at least 3. It can be shown that "aba" is the lexicographically smallest one.

 

Constraints:

  • 1 <= a.length, b.length, c.length <= 100
  • a, b, c consist only of lowercase English letters.

代码结果

运行时间: 139 ms, 内存: 16.0 MB


/*
 * 思路:
 * 1. 通过Java Stream API处理多个可能的字符串组合
 * 2. 合并每两个字符串,生成包含它们的最短字符串
 * 3. 比较所有可能的结果,选择最短且字典序最小的一个
 */

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

public class SolutionStream {
    private static String merge(String s1, String s2) {
        for (int i = 0; i < s1.length(); i++) {
            if (s2.startsWith(s1.substring(i))) {
                return s1.substring(0, i) + s2;
            }
        }
        return s1 + s2;
    }

    public static String findShortestSuperstring(String a, String b, String c) {
        List<String> combinations = Arrays.asList(
            merge(merge(a, b), c),
            merge(merge(a, c), b),
            merge(merge(b, a), c),
            merge(merge(b, c), a),
            merge(merge(c, a), b),
            merge(merge(c, b), a)
        );

        return combinations.stream()
                .sorted(Comparator.comparingInt(String::length).thenComparing(String::compareTo))
                .collect(Collectors.toList())
                .get(0);
    }

    public static void main(String[] args) {
        System.out.println(findShortestSuperstring("abc", "bca", "aaa")); // 输出: "aaabca"
        System.out.println(findShortestSuperstring("ab", "ba", "aba"));   // 输出: "aba"
    }
}

解释

方法:

此题解采用的方法是首先定义一个合并两个字符串的函数,该函数通过检查字符串的前缀和后缀是否相匹配来找到最短的合并方式。如果一个字符串是另一个的子串,则直接返回包含关系中的较大字符串。如果不是,函数尝试寻找最大的公共前后缀,并在此基础上合并两个字符串。主函数中,通过考虑所有字符串的排列组合,利用这个合并函数逐步合并三个字符串,保证每次合并都尝试得到最短的可能字符串。最终比较所有可能的合并结果,选择长度最短的,如果长度相同则选择字典序最小的字符串。

时间复杂度:

O(n^2)

空间复杂度:

O(n)

代码细节讲解

🦆
在合并函数中使用前缀和后缀匹配来确定合并方式的原理是什么?能否详细解释其有效性?
在合并函数中,前缀和后缀匹配的原理基于最大公共子序列的概念。如果两个字符串的结尾和开头部分重叠,那么可以通过重叠部分来合并,从而避免重复和减少总长度。例如,如果字符串 'abc' 和 'bcd' 合并,因为 'abc' 的 'bc' 和 'bcd' 的 'bc' 重叠,合并结果为 'abcd',比简单拼接 'abcbcd' 短。这种方法有效地减少了合并后的字符串长度,对于减少存储空间和提高处理效率非常有帮助。
🦆
合并函数中如果没有找到公共的前缀或后缀,直接将两个字符串拼接,这种情况下是否可能错过更优的合并结果?
如果合并函数中没有找到公共的前缀或后缀,直接拼接两个字符串是一种保守而简单的合并策略。然而,这种方法可能错过更优的合并结果,特别是在涉及到多个字符串合并时。例如,对于字符串 'abc', 'cde', 'efgh',如果先合并 'abc' 和 'cde',未发现重叠,则结果为 'abccde'。但若先考虑 'cde' 和 'efgh',因重叠得到 'cdefgh',再与 'abc' 合并时可得到 'abcdefgh'。因此,这种方法可能不总是产生最短的合并结果。
🦆
题解中提到了对所有字符串排列进行合并操作,这种方法在哪些情况下可能不是最优的?
尽管考虑所有字符串的排列并合并可以在某些情况下找到最短的合并字符串,但这种方法在效率上并不总是最优的,特别是当字符串数量增加时。对字符串进行全排列会导致计算量急剧增加,因为排列的数量是字符串数量的阶乘,这在实际应用中可能导致效率问题。此外,这种方法可能在某些特殊的字符串组合情况下,未必能得到真正的最短结果,尤其是涉及到多重重叠或特殊顺序的情况。
🦆
在选择最短字符串结果时,如何处理多个结果长度相同但字典序不同的情况?具体的比较逻辑是怎样的?
在选择最短字符串结果时,如果遇到多个合并结果长度相同,题解中采用的策略是选择字典序最小的字符串。具体比较逻辑是在更新结果字符串时,不仅比较字符串长度,还要比较字典序。如果新的字符串长度小于当前最短字符串,或者长度相同但字典序更小,则更新结果字符串。这样可以确保最终结果不仅长度最短,而且在多个最短结果中字典序最小。

相关问题