leetcode
leetcode 2751 ~ 2800
统计以给定字符开头和结尾的子字符串总数

统计以给定字符开头和结尾的子字符串总数

难度:

标签:

题目描述

You are given a string s and a character c. Return the total number of substrings of s that start and end with c.

 

Example 1:

Input: s = "abada", c = "a"

Output: 6

Explanation: Substrings starting and ending with "a" are: "abada", "abada", "abada", "abada", "abada", "abada".

Example 2:

Input: s = "zzz", c = "z"

Output: 6

Explanation: There are a total of 6 substrings in s and all start and end with "z".

 

Constraints:

  • 1 <= s.length <= 105
  • s and c consist only of lowercase English letters.

代码结果

运行时间: 21 ms, 内存: 16.5 MB


/*
 * 思路:
 * 使用Java Stream API来实现同样的逻辑。
 * 首先将字符串s转换成字符流,找到所有字符c出现的索引位置,
 * 对于每一个索引位置i,使用一个嵌套流来计算从i开始到后面所有的以字符c结尾的子字符串数量。
 */
import java.util.stream.IntStream;

public class SolutionStream {
    public long countSubstrings(String s, char c) {
        return IntStream.range(0, s.length())
                .filter(i -> s.charAt(i) == c)
                .mapToLong(i -> IntStream.range(i, s.length())
                        .filter(j -> s.charAt(j) == c)
                        .count())
                .sum();
    }
    public static void main(String[] args) {
        SolutionStream sol = new SolutionStream();
        System.out.println(sol.countSubstrings("abada", 'a')); // 6
        System.out.println(sol.countSubstrings("zzz", 'z'));   // 6
    }
}

解释

方法:

该题解的核心思路是首先统计字符 c 在字符串 s 中出现的次数 n。然后利用组合数学的知识,计算出所有以字符 c 开头和结尾的子字符串的数量。如果 c 在 s 中出现n次,那么任选两个位置组成的子字符串都将以 c 作为开头和结尾,这样的选择方式共有 C(n, 2) = n*(n-1)/2 种。此外,每个单独的字符 c 本身也是一个符合条件的子字符串,因此总数还要加上 n,即总数为 n*(n+1)/2。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
为什么在计算以字符c开头和结尾的子字符串数量时使用组合公式C(n, 2)加上n,而不是其他计算方式?
组合公式 C(n, 2) 用于计算从 n 个元素中任选两个元素的组合方式数量,这里的 n 个元素是字符 c 在字符串 s 中的每次出现。当我们选择两个 c 字符,一个作为子字符串的开头,另一个作为结尾时,这两个位置之间的任何字符都是子字符串的一部分,因此 C(n, 2) 计算了所有可能的子字符串(长度至少为 2)的数量。加上 n 是因为每个单独的字符 c 也算作一个长度为 1 的子字符串。这种计算方式简洁且直接反映了问题的组合本质,是最自然的计算方法。
🦆
在计算字符c在字符串s中的出现次数时,如果字符串非常长,是否有更高效的方法来处理大数据量?
在字符串非常长的情况下,使用 s.count(c) 已经是计算字符 c 出现次数的高效方法之一,因为它是一个线性时间复杂度的操作,即 O(n),其中 n 是字符串 s 的长度。尽管如此,如果处理的是超大数据量或需要重复查询多个字符的频次,可以考虑一次性遍历字符串统计所有字符的出现频次,将结果存储在哈希表中,以后每次查询任何字符的频次都可以在常数时间 O(1) 内完成。这种方法前期需要一次遍历,但可以显著加快后续的查询速度。
🦆
该算法假设字符c至少出现一次,如果c在s中一次都没有出现,返回值应该是多少?这个处理在当前的实现中是否正确?
如果字符 c 在字符串 s 中一次都没有出现,那么 n(c 的出现次数)将为 0。根据公式 n*(n+1)/2,当 n 为 0 时,计算结果也是 0。这表示没有任何子字符串以 c 为开头和结尾,这是符合逻辑的结果。因此,当前实现在处理 c 不出现在 s 中的情况下是正确的,它正确地返回了 0。

相关问题