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;
    }
}
相关推荐
ChoSeitaku13 分钟前
链表循环及差集相关算法题|判断循环双链表是否对称|两循环单链表合并成循环链表|使双向循环链表有序|单循环链表改双向循环链表|两链表的差集(C)
c语言·算法·链表
DdddJMs__13518 分钟前
C语言 | Leetcode C语言题解之第557题反转字符串中的单词III
c语言·leetcode·题解
Fuxiao___22 分钟前
不使用递归的决策树生成算法
算法
我爱工作&工作love我27 分钟前
1435:【例题3】曲线 一本通 代替三分
c++·算法
白-胖-子1 小时前
【蓝桥等考C++真题】蓝桥杯等级考试C++组第13级L13真题原题(含答案)-统计数字
开发语言·c++·算法·蓝桥杯·等考·13级
workflower1 小时前
数据结构练习题和答案
数据结构·算法·链表·线性回归
好睡凯1 小时前
c++写一个死锁并且自己解锁
开发语言·c++·算法
Sunyanhui11 小时前
力扣 二叉树的直径-543
算法·leetcode·职场和发展
一个不喜欢and不会代码的码农1 小时前
力扣105:从先序和中序序列构造二叉树
数据结构·算法·leetcode
前端郭德纲2 小时前
浏览器是加载ES6模块的?
javascript·算法