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;
    }
}
相关推荐
karmueo4619 分钟前
视频序列和射频信号多模态融合算法Fusion-Vital解读
算法·音视频·多模态
小汉堡编程1 小时前
数据结构——vector数组c++(超详细)
数据结构·c++
写代码的小球3 小时前
求模运算符c
算法
雾里看山5 小时前
顺序表VS单链表VS带头双向循环链表
数据结构·链表
大千AI助手7 小时前
DTW模版匹配:弹性对齐的时间序列相似度度量算法
人工智能·算法·机器学习·数据挖掘·模版匹配·dtw模版匹配
好好研究7 小时前
学习栈和队列的插入和删除操作
数据结构·学习
YuTaoShao8 小时前
【LeetCode 热题 100】48. 旋转图像——转置+水平翻转
java·算法·leetcode·职场和发展
生态遥感监测笔记8 小时前
GEE利用已有土地利用数据选取样本点并进行分类
人工智能·算法·机器学习·分类·数据挖掘
Tony沈哲9 小时前
macOS 上为 Compose Desktop 构建跨架构图像处理 dylib:OpenCV + libraw + libheif 实践指南
opencv·算法