You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何以低时间复杂度统计满足频率约束的有效子串数量?

问题描述

给定仅由字符a-g组成的字符串,统计其中满足子串内任意字符的频率不超过该子串中不同字符数量的子串总数。

  • 示例:输入"abaa",输出为8。有效子串包括:a、b、a、a、ab、ba、aba、baa
  • 约束条件:字符串长度范围为1≤n≤10^5,字符仅包含a-g
尝试的解法及问题

我尝试用频率数组+滑动窗口思路求解,但移动左指针时会遗漏部分长有效子串,代码无法输出正确结果。附Java代码如下:

public class Main {
        public static int solve(String str) {
            int n = str.length();
            int[] freq = new int[7]; // 统计'a'-'g'的频率
            int left = 0, right = 0, distinct = 0, count = 0;

            while (right < n) {
                int rightChar = str.charAt(right) - 'a';
                if (freq[rightChar] == 0) distinct++; // 窗口新增不同字符
                freq[rightChar]++;

                // 仅检查当前右指针字符的频率是否超过distinct,存在逻辑漏洞
                while (freq[rightChar] > distinct) {
                    int leftChar = str.charAt(left) - 'a';
                    freq[leftChar]--;
                    if (freq[leftChar] == 0) distinct--; // 移除了一个不同字符
                    left++;
                }

                // 原本打算统计以right结尾的有效子串数量,但当前窗口逻辑不正确
                //count += (right - left + 1);
                right++;
            }

            return count;
        }

        public static void main(String[] args) {
            System.out.println(solve("abaa"));  // 期望输出: 8 
            System.out.println(solve("abab"));  // 期望输出: 10
            System.out.println(solve("aacd"));  // 期望输出: 9 

        }

    }

另一种思路是枚举所有子串,用哈希表统计频率后验证有效性,但时间复杂度为O(n²k)(k为字符种类数,此处k=7),对于n=1e5的场景效率极低,无法满足性能要求。

高效解法:改进滑动窗口

由于字符仅包含7种,我们可以在滑动窗口中维护频率数组和当前窗口的不同字符数distinct,每次扩展右指针后,循环检查窗口内是否存在字符的频率超过distinct,若存在则移动左指针缩小窗口,直到窗口满足条件。此时,以右指针结尾的所有子串(从左指针到右指针)均为有效子串,将其数量计入总数。

优化后的Java代码

public class Main {
    public static int solve(String str) {
        int n = str.length();
        int[] freq = new int[7];
        int left = 0, distinct = 0, count = 0;

        for (int right = 0; right < n; right++) {
            int c = str.charAt(right) - 'a';
            if (freq[c] == 0) {
                distinct++;
            }
            freq[c]++;

            // 循环检查窗口是否有效:所有字符频率 ≤ distinct
            while (true) {
                boolean invalid = false;
                for (int i = 0; i < 7; i++) {
                    if (freq[i] > distinct) {
                        invalid = true;
                        break;
                    }
                }
                if (!invalid) break;
                // 移动左指针,调整窗口
                int leftC = str.charAt(left) - 'a';
                freq[leftC]--;
                if (freq[leftC] == 0) {
                    distinct--;
                }
                left++;
            }

            // 统计以当前right结尾的有效子串数量
            count += right - left + 1;
        }
        return count;
    }

    public static void main(String[] args) {
        System.out.println(solve("abaa"));  // 输出: 8
        System.out.println(solve("abab"));  // 输出: 10
        System.out.println(solve("aacd"));  // 输出: 9
    }
}

时间复杂度分析

每次扩展右指针后,检查窗口有效性最多遍历7个字符,移动左指针的总次数不超过n次,因此总时间复杂度为O(n*7)=O(n),完全满足n=1e5的约束条件。

内容的提问来源于stack exchange,提问作者CodeCrusader

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 20:19:58