leetcode
leetcode 1701 ~ 1750
最美子字符串的数目

最美子字符串的数目

难度:

标签:

题目描述

代码结果

运行时间: 803 ms, 内存: 17.0 MB


/*
 * 思路:
 * 1. 利用Java Stream API进行流式处理。
 * 2. 和普通Java代码思路一样,只是在处理过程中使用Stream进行处理。
 */

import java.util.HashMap;
import java.util.stream.IntStream;

public class BeautifulSubstringsStream {
    public int countBeautifulSubstrings(String word) {
        int[] prefixOddEven = new int[10];
        HashMap<Integer, Integer> map = new HashMap<>();
        final int[] currentState = {0};
        final int[] result = {0};

        map.put(0, 1); // 初始化前缀状态0的出现次数

        IntStream.range(0, word.length()).forEach(i -> {
            int index = word.charAt(i) - 'a';
            prefixOddEven[index] ^= 1; // 更新前缀状态
            currentState[0] = 0;
            for (int j = 0; j < 10; j++) {
                currentState[0] |= (prefixOddEven[j] << j); // 计算当前前缀状态
            }
            result[0] += map.getOrDefault(currentState[0], 0);
            map.put(currentState[0], map.getOrDefault(currentState[0], 0) + 1);
        });
        return result[0];
    }

    public static void main(String[] args) {
        BeautifulSubstringsStream bss = new BeautifulSubstringsStream();
        System.out.println(bss.countBeautifulSubstrings("aba")); // 4
        System.out.println(bss.countBeautifulSubstrings("aabb")); // 9
        System.out.println(bss.countBeautifulSubstrings("he")); // 2
    }
}

解释

方法:

这个题解使用了位运算和前缀XOR的概念来高效地解决问题。首先,每个字母可以映射到一个10位的二进制数中的某一位(因为字母'a'到'j'共有10个)。对于字符串中的每个字符,通过一个异或操作更新当前的前缀XOR值。这个前缀XOR在二进制表示中,每位的1表示对应位置的字母出现奇数次。题解中使用了一个字典来存储每个前缀XOR出现的次数。然后,计算所有可能的最美子字符串的数量。只要当前的前缀XOR或者与之前某个前缀XOR的差异正好是一位(即异或结果中只有一个位是1),则表示这之间的子字符串是最美的。总体上,此方法避免了直接检查每个子字符串,而是通过巧妙地利用前缀XOR来统计满足条件的子字符串数量。

时间复杂度:

O(n + K^2),其中K是唯一前缀XOR值的数量,最坏情况下K为1024

空间复杂度:

O(K),其中K为前缀XOR的不同值的数量,最坏情况下为1024

代码细节讲解

🦆
在位运算方法中,每个字母映射到一个10位二进制数的具体位是如何决定的?为什么选择异或操作来更新前缀XOR值?
每个字母映射到一个10位二进制数的某一位是基于其字母顺序决定的。例如,'a'到'j'分别映射到从第0位到第9位。具体实现是通过`1 << (ord(s) - ord('a'))`,这样'a'映射为1(二进制0000000001),'b'映射为2(二进制0000000010),依此类推。选择异或操作更新前缀XOR值是因为异或操作具有几个关键性质:它可以有效地切换位值(如果某位为1则切换为0,如果为0则切换为1),且对于两次相同的异或操作,原始值会被恢复。这使得异或操作非常适合于跟踪字符出现次数的奇偶性,因为每遇到同一个字母一次,其对应的位就会切换一次。
🦆
题解提到的`如果当前的前缀XOR或者与之前某个前缀XOR的差异正好是一位`,这里的逻辑是否确保了子字符串的最美条件,即至多一个字母出现奇数次?
是的,这个逻辑确实确保了子字符串符合最美条件。当前缀XOR值与之前某个前缀XOR值的差异正好是一位时(即两者的异或结果中只有一个位是1),这表明从上一个前缀到当前前缀之间的子字符串中,只有一个字母的出现次数从偶数变为奇数或从奇数变为偶数。这意味着该子字符串中除了这一个字母可能出现奇数次外,其他所有字母均出现偶数次,从而满足最美子字符串的条件。
🦆
在实际应用中,如何处理和优化大量重复的前缀XOR值,以避免不必要的重复计算和存储?
为了处理和优化重复的前缀XOR值,可以使用哈希表(或字典)来存储每个唯一前缀XOR值出现的次数。这种方法不仅避免了重复计算,因为我们可以直接从哈希表中获取信息,而不是重新计算每个子字符串,同时也减少了存储需求,因为我们只存储每个唯一的前缀XOR值及其出现次数,而不是每个子字符串的前缀XOR值。此外,可进一步优化内存使用和检索效率,例如通过限制哈希表的大小,或使用更高效的数据结构来处理冲突,从而提高算法的整体性能和效率。

相关问题