leetcode
leetcode 2751 ~ 2800
统计前后缀下标对 II

统计前后缀下标对 II

难度:

标签:

题目描述

You are given a 0-indexed string array words.

Let's define a boolean function isPrefixAndSuffix that takes two strings, str1 and str2:

  • isPrefixAndSuffix(str1, str2) returns true if str1 is both a prefix and a suffix of str2, and false otherwise.

For example, isPrefixAndSuffix("aba", "ababa") is true because "aba" is a prefix of "ababa" and also a suffix, but isPrefixAndSuffix("abc", "abcd") is false.

Return an integer denoting the number of index pairs (i, j) such that i < j, and isPrefixAndSuffix(words[i], words[j]) is true.

 

Example 1:

Input: words = ["a","aba","ababa","aa"]
Output: 4
Explanation: In this example, the counted index pairs are:
i = 0 and j = 1 because isPrefixAndSuffix("a", "aba") is true.
i = 0 and j = 2 because isPrefixAndSuffix("a", "ababa") is true.
i = 0 and j = 3 because isPrefixAndSuffix("a", "aa") is true.
i = 1 and j = 2 because isPrefixAndSuffix("aba", "ababa") is true.
Therefore, the answer is 4.

Example 2:

Input: words = ["pa","papa","ma","mama"]
Output: 2
Explanation: In this example, the counted index pairs are:
i = 0 and j = 1 because isPrefixAndSuffix("pa", "papa") is true.
i = 2 and j = 3 because isPrefixAndSuffix("ma", "mama") is true.
Therefore, the answer is 2.  

Example 3:

Input: words = ["abab","ab"]
Output: 0
Explanation: In this example, the only valid index pair is i = 0 and j = 1, and isPrefixAndSuffix("abab", "ab") is false.
Therefore, the answer is 0.

 

Constraints:

  • 1 <= words.length <= 105
  • 1 <= words[i].length <= 105
  • words[i] consists only of lowercase English letters.
  • The sum of the lengths of all words[i] does not exceed 5 * 105.

代码结果

运行时间: 159 ms, 内存: 32.3 MB


/* 
题目思路:
使用Java Stream来解决这个问题。我们可以通过双重流循环来遍历所有可能的(i, j)对,并使用filter方法来筛选出符合条件的对,最终计算它们的数量。
*/
import java.util.stream.IntStream;

public class Solution {
    public boolean isPrefixAndSuffix(String str1, String str2) {
        int len1 = str1.length();
        int len2 = str2.length();
        if (len1 > len2) return false;
        return str2.startsWith(str1) && str2.endsWith(str1);
    }

    public long countPrefixAndSuffixPairs(String[] words) {
        return IntStream.range(0, words.length)
                .boxed()
                .flatMap(i -> IntStream.range(i + 1, words.length)
                        .filter(j -> isPrefixAndSuffix(words[i], words[j]))
                        .boxed())
                .count();
    }

    public static void main(String[] args) {
        Solution solution = new Solution();
        String[] words = {"a","aba","ababa","aa"};
        System.out.println(solution.countPrefixAndSuffixPairs(words)); // 输出:4
    }
}

解释

方法:

此题解采用了逆序遍历与哈希表的结合来优化查询和统计过程。首先,从数组的尾部开始遍历,使用哈希表s2c来记录遍历过的每个字符串及其出现次数。对于每个字符串words[i],检查它是否为已记录在哈希表中的每个字符串的前缀和后缀。如果是,则累加对应字符串的计数到结果中。此方法避免了重复的字符串比较,利用哈希表快速地检索和更新字符串的出现次数。

时间复杂度:

O(n^2 * l)

空间复杂度:

O(n * l)

代码细节讲解

🦆
为什么选择从数组的尾部向前遍历而不是从头部开始遍历?这种遍历方向对算法的效率有何影响?
从数组的尾部向前遍历可以有效地利用哈希表记录已经遍历过的字符串及其出现次数,这样在遍历到每一个新字符串时,可以直接使用哈希表检查该字符串是否为任一已遍历字符串的前后缀。如果从数组头部开始遍历,每次遇到新字符串都需要向后检查所有未遍历的字符串,这将导致大量的重复比较和计算。逆序遍历让每个字符串在进入哈希表前先作为前缀和后缀候选,从而减少了计算量并提高了效率。
🦆
哈希表s2c在算法中扮演了什么角色,它是如何帮助减少计算量的?
哈希表s2c在算法中扮演了关键的数据记录角色。它记录每一个已遍历字符串及其出现次数,使得在遍历到新的字符串时,可以直接利用哈希表来快速检查这个新字符串是否为任何已记录字符串的前缀或后缀。这种方法避免了对每个新字符串进行大量的字符串比较,从而显著减少了计算量。此外,使用哈希表还可以快速更新和查询字符串的计数,进一步提高算法的执行效率。
🦆
在更新哈希表s2c时,为什么选择使用 get 方法,并且如何确保它的正确性和高效性?
在更新哈希表s2c时,使用get方法可以方便地返回指定键的值,如果键不存在,则返回一个默认值,通常是0。这样可以在一行代码内完成查询和默认值处理,简化了代码并减少了错误的可能性。使用get方法更新哈希表不仅保证了代码的简洁性,还保持了高效性,因为它避免了先检查键是否存在再进行赋值的多步骤操作。这种方式确保了算法的正确性和高效性,因为它能够快速响应键值对的检索和更新需求。

相关问题