LeetCode每日一题3261---统计满足 K 约束的子字符串数量 II

一、题目描述

给你一个 二进制 字符串 s 和一个整数 k

另给你一个二维整数数组 queries ,其中 queries[i] = [li, ri]

如果一个 二进制字符串 满足以下任一条件,则认为该字符串满足 k 约束:

字符串中 0 的数量最多为 k

字符串中 1 的数量最多为 k

返回一个整数数组 answer ,其中 answer[i] 表示 s[li..ri] 中满足 k 约束 的 子字符串的数量。

示例 1:

输入:s = "0001111", k = 2, queries = [[0,6]]

输出:[26]

解释:

对于查询 [0, 6], s[0...6] = "0001111" 的所有子字符串中,除 s[0...5] = "000111" 和 s[0...6] = "0001111" 外,其余子字符串都满足 k 约束。

示例 2:

输入:s = "010101", k = 1, queries = [[0,5],[1,4],[2,3]]

输出:[15,9,3]

解释:

s 的所有子字符串中,长度大于 3 的子字符串都不满足 k 约束。

提示:

1 <= s.length <= 105

s[i] 是 '0' 或 '1'

1 <= k <= s.length

1 <= queries.length <= 105

queries[i] == [li, ri]

0 <= li <= ri < s.length

所有查询互不相同

二、解题思路

这道题目与统计满足 K 约束的子字符串数量 I相似,就是需要处理多个子串,完全可以利用上一次的函数进行求解,但是由于这次的字符串长度太大,会导致超出时间限制,因此需要特殊的方法处理,可以使用双指针 + 前缀和 + 二分

三、代码

1、普通方法(超出时间限制)

cpp 复制代码
class Solution {
public:
    // 计算符合条件的子串个数
    int countKConstraintSubstrings1(string& s, int k) {
        int l = 0, count = 0, one = 0, zero = 0;
        for (int i = 0; i < s.size(); i++) {
            if (s[i] == '1') one++;
            else zero++;

            // Shrink the window until both one and zero counts are <= k
            while (one > k && zero > k) {
                if (s[l++] == '1') one--;
                else zero--;
            }

            // Count all valid substrings ending at i
            count += i - l + 1;
        }
        return count;
    }

    vector<long long> countKConstraintSubstrings(string s, int k, vector<vector<int>>& queries) {
        vector<long long> result(queries.size());
        
        // 针对每个查询直接计算符合条件的子串个数
        for (int i = 0; i < queries.size(); i++) {
            int left = queries[i][0], right = queries[i][1];
            
            // 直接截取查询区间的字符串
            string substring = s.substr(left, right - left + 1);
            result[i] = countKConstraintSubstrings1(substring, k); // 计算当前区间内符合条件的子串个数
        }

        return result;
    }
};

2、双指针 + 前缀和 + 二分

java 复制代码
class Solution {
    public long[] countKConstraintSubstrings(String s, int k, int[][] queries) {
        int n = s.length();
        char[] chars = s.toCharArray();
        int[] f = new int[n + 1];
        long[] sumF = new long[n + 1], sum = new long[n + 1];
        for (int i = 1, j = 1, sum1 = 0; i <= n; i++) {
            sum1 += chars[i - 1] - '0';
            while (sum1 > k && i - j + 1 - sum1 > k) {
                sum1 -= chars[j - 1] - '0';
                j++;
            }
            f[i] = j;
            sumF[i] = sumF[i - 1] + f[i];
            sum[i] = sum[i - 1] + i - j + 1;
        }

        int m = queries.length;
        long[] ans = new long[m];
        for (int i = 0; i < m; i++) {
            int l = queries[i][0] + 1, r = queries[i][1] + 1;
            ans[i] = sum[r] - sum[l - 1];

            int lo = l, hi = r, idx = -1;
            while (lo <= hi) {
                int mid = lo + hi >> 1;
                if (f[mid] < l) {
                    idx = mid;
                    lo = mid + 1;
                } else {
                    hi = mid - 1;
                }
            }

            if (idx != -1) {
                ans[i] -= (long) (idx - l + 1) * l - (sumF[idx] - sumF[l - 1]);
            }
        }

        return ans;
    }
}
相关推荐
千天夜9 分钟前
多源多点路径规划:基于启发式动态生成树算法的实现
算法·机器学习·动态规划
从以前14 分钟前
准备考试:解决大学入学考试问题
数据结构·python·算法
.Vcoistnt37 分钟前
Codeforces Round 994 (Div. 2)(A-D)
数据结构·c++·算法·贪心算法·动态规划
ALISHENGYA1 小时前
全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之分支结构(实战训练三)
数据结构·c++·算法·图论
Dream it possible!3 小时前
LeetCode 热题 100_LRU 缓存(35_146_中等_C++)(哈希表 + 双向链表)(构造函数声明+初始化列表=进行变量初始化和赋值)
c++·leetcode·缓存
我码玄黄3 小时前
正则表达式优化之算法和效率优化
前端·javascript·算法·正则表达式
Solitudefire4 小时前
蓝桥杯刷题——day9
算法·蓝桥杯
三万棵雪松5 小时前
1.系统学习-线性回归
算法·机器学习·回归·线性回归·监督学习
Easy数模5 小时前
基于LR/GNB/SVM/KNN/DT算法的鸢尾花分类和K-Means算法的聚类分析
算法·机器学习·支持向量机·分类·聚类
2401_858286115 小时前
117.【C语言】数据结构之排序(选择排序)
c语言·开发语言·数据结构·笔记·算法·排序算法