leetcode
leetcode 1351 ~ 1400
字符串的好分割数目

字符串的好分割数目

难度:

标签:

题目描述

代码结果

运行时间: 70 ms, 内存: 18.8 MB


/*
 * 思路:
 * 1. 使用 Java Stream API 进行字符串处理。
 * 2. 统计每个位置左边和右边不同字符的数量。
 * 3. 用两个数组 leftCounts 和 rightCounts 分别记录从左到右和从右到左的不同字符数量。
 * 4. 最后判断 leftCounts[i] 是否等于 rightCounts[i+1]。
 */

import java.util.*;
import java.util.stream.Collectors;

public class GoodSplitsStream {
    public int numSplits(String s) {
        int n = s.length();
        int[] leftCounts = new int[n];
        int[] rightCounts = new int[n];
        Set<Character> leftSet = new HashSet<>();
        Set<Character> rightSet = new HashSet<>();
        
        // 从左到右统计不同字符数
        IntStream.range(0, n).forEach(i -> {
            leftSet.add(s.charAt(i));
            leftCounts[i] = leftSet.size();
        });
        
        // 从右到左统计不同字符数
        IntStream.iterate(n - 1, i -> i >= 0, i -> i - 1).forEach(i -> {
            rightSet.add(s.charAt(i));
            rightCounts[i] = rightSet.size();
        });
        
        // 判断好分割数量
        long goodSplits = IntStream.range(0, n - 1)
                                   .filter(i -> leftCounts[i] == rightCounts[i + 1])
                                   .count();
        
        return (int) goodSplits;
    }
    
    public static void main(String[] args) {
        GoodSplitsStream gss = new GoodSplitsStream();
        System.out.println(gss.numSplits("aacaba")); // 输出: 2
        System.out.println(gss.numSplits("abcd"));   // 输出: 1
        System.out.println(gss.numSplits("aaaaa"));  // 输出: 4
        System.out.println(gss.numSplits("acbadbaada")); // 输出: 2
    }
}

解释

方法:

这个题解采用了前缀和和后缀和的思路来计算字符串中不同字符的数量。首先,定义一个辅助函数 check,它会遍历输入字符串并使用一个集合来追踪遇到的不同字符,并将当前不同字符的计数存储在一个列表中。函数返回这个列表。对于原始字符串 s,我们计算一个前缀和 nums1,它记录了从字符串开始到当前位置的不同字符数量。对于翻转后的字符串 s[::-1],我们同样计算一个类似的列表 nums2,然后将其反转,使之变成后缀和。最后,通过遍历这两个列表直到倒数第二个字符,并比较前缀和和对应的后缀和是否相等,来确定是否是好分割。若相等,则增加答案计数器 ans。这种方法有效地利用了前缀和和后缀和的对比来避免重复计算,从而优化了性能。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
题解中用到的`check`函数在遍历字符串时,是否有考虑到字符编码的不同,比如ASCII与Unicode?对于包含非常规字符的字符串,该方法的准确性如何?
题解中的`check`函数使用Python的`set`来记录字符,Python的字符串是基于Unicode编码的。这意味着无论输入字符串中的字符属于ASCII还是任何其他Unicode字符,`set`都能正确地处理和记录这些字符。因此,这种方法对于包含非常规字符的字符串同样是准确的,可以有效地处理多语言文本或特殊符号。
🦆
在比较前缀和后缀是否相等的过程中,有没有可能出现由于字符串长度不同但字符种类相同的情况,从而影响`好分割`的判断?
在这个题解中,比较前缀和和后缀和是否相等的过程是在长度相同的位置进行的。`nums1`列表记录了从左到右每个位置的不同字符数量,而`nums2`列表则记录了从右到左每个位置的不同字符数量,并已经反转以匹配前缀位置。因此,每次比较都是在相同长度的切片上进行,不会出现由于字符串长度不同而影响判断的情况。
🦆
为什么在实现时选择使用`set`来记录已经遇到的字符,而不是使用`dict`或其他数据结构?使用`set`有什么特别的优势吗?
`set`在Python中是一个高效的数据结构,特别适用于需要快速检索、添加和删除元素的场景。在这种情况下,我们需要检查一个字符是否已经被记录过,`set`提供了平均时间复杂度为O(1)的成员检查和插入操作。使用`dict`可能也可以实现同样的功能,但在这种情况下使用`set`更为直接和高效,因为我们只关心字符的存在性,不关心字符的数量或其他属性。
🦆
在实现好分割的检测时,题解仅在遍历到字符串的倒数第二个字符停止,这种做法的原因是什么?是否与数组边界条件有关?
这种做法直接关联到数组的边界条件。在寻找好分割的过程中,如果遍历到字符串的最后一个字符,则后缀部分将为空,而前缀部分将是整个字符串。这种情况下,前缀和后缀无法形成有效的分割(因为至少需要有字符在后缀中)。因此,遍历到倒数第二个字符是为了确保后缀至少包含一个字符,从而满足分割的基本要求。

相关问题