3258. Count Substrings That Satisfy K-Constraint I
Problem Description
You are given a binary string s
and an integer k
.
A binary string satisfies the k-constraint if either of the following conditions holds:
- The number of
0
s in the string is at mostk
. - The number of
1
s in the string is at mostk
.
Return an integer denoting the number of non-empty substrings of s
that satisfy the k-constraint.
Intuition
The solution uses a sliding window approach. The idea is to maintain a window containing a current substring of s
and keep track of how many 0
s and 1
s are present within this window.
The approach is as follows:
- Initialize counters for
0
s and1
s in the current window. Also, maintain pointersl
andr
representing the left and right boundary of the window. - Traverse the string character by character. For each character, update the count of
0
s or1
s, depending on whether the character is a0
or a1
. - If both
0
and1
counts exceedk
, keep increasing the left boundary (l
) until at least one count isk
or smaller. This ensures that the current window satisfies the k-constraint. - Each time the window is shifted, calculate the number of valid substrings from the current valid window, which is the number of positions
r - l + 1
. - Continue expanding the right boundary until the end of the string.
The algorithm efficiently counts valid substrings while iterating through the string with a time complexity of O(n)
, where n
is the length of s
.
Learn more about Sliding Window patterns.
Solution Approach
The solution employs the Sliding Window technique, which is well-suited for problems involving arrays or strings where we need to find a condition that holds for contiguous subarrays or substrings.
- Initialization: We begin by initializing two variables
cnt
andans
. Thecnt
array stores the count of0
s and1
s in the current window. The variableans
will keep track of the total number of substrings that satisfy the k-constraint. Additionally, a variablel
is initialized as 0, which marks the left boundary of our sliding window.
cnt = [0, 0] ans = l = 0
- Window Expansion: Iterate over each character in the binary string
s
using its indexr
. Convert the character to an integer (0
or1
) and increase its count in thecnt
array.
for r, x in enumerate(map(int, s)):
cnt[x] += 1
- Valid Window Check: After updating the count, check if both counts (
cnt[0]
andcnt[1]
) exceedk
. If they do, it means the substring starting froml
tor
is invalid. Hence, increment the left boundaryl
until at least one count isk
or less.
while cnt[0] > k and cnt[1] > k:
cnt[int(s[l])] -= 1
l += 1
- Counting Valid Substrings: If the current window satisfies the k-constraint, all substrings starting with an index between
l
andr
are valid. Thus, the total number of such substrings isr - l + 1
. Add this count toans
.
ans += r - l + 1
- Result: After the loop completes,
ans
will contain the total number of substrings that fulfill the k-constraint.
Finally, return ans
as the result.
return ans
This approach efficiently finds all valid substrings with a time complexity of O(n)
, iterating through the string a minimal number of times due to the sliding window mechanism.
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through an example to illustrate the solution approach.
Consider the binary string s = "11001"
and the integer k = 2
.
We'll apply the sliding window technique as follows:
-
Initialization:
cnt = [0, 0]
to track the number of0
s and1
s in the window.ans = 0
to accumulate the total number of valid substrings.l = 0
to mark the left boundary of the window.
-
Window Expansion: Our goal is to iterate over every character in
s
and expand the window by including each character at the right endr
:- At
r = 0
,x = 1
: Updatecnt
to[0, 1]
. - At
r = 1
,x = 1
: Updatecnt
to[0, 2]
. The window is valid as the number of0
s or1
s is less than or equal tok
. - Count the valid substrings from
l = 0
tor = 1
.ans = ans + (r - l + 1) = 0 + 2 = 2
.
- At
-
Continue Expanding:
- At
r = 2
,x = 0
: Updatecnt
to[1, 2]
. Window[0,2]
is still valid. - Count the valid substrings:
ans = 2 + (r - l + 1) = 5
. - At
r = 3
,x = 0
: Updatecnt
to[2, 2]
. This window[0,3]
remains valid. - Count the valid substrings:
ans = 5 + (r - l + 1) = 9
.
- At
-
Check Constraints:
- At
r = 4
,x = 1
: Updatecnt
to[2, 3]
. Now, both counts exceedk
. We need to incrementl
until our window is valid. - Increment
l
to 1:cnt
becomes[2, 2]
, making the window[1,4]
valid again. - Count the valid substrings:
ans = 9 + (r - l + 1) = 13
.
- At
-
Final Result:
- At the end of the iteration,
ans = 13
which is the total number of substrings that satisfy the k-constraint.
- At the end of the iteration,
In this example, we efficiently counted all qualifying substrings using a sliding window, ensuring time complexity of O(n).
Solution Implementation
1class Solution:
2 def countKConstraintSubstrings(self, s: str, k: int) -> int:
3 # Initialize counters for '0' and '1'
4 cnt = [0, 0]
5 # Initialize the answer counter and left pointer
6 ans = l = 0
7
8 # Iterate over the string `s` while mapping characters to integers
9 for r, x in enumerate(map(int, s)):
10 # Increase the count of the current character
11 cnt[x] += 1
12
13 # If both '0' and '1' exceed the allowed count `k`, adjust the left boundary
14 while cnt[0] > k and cnt[1] > k:
15 # Decrease the count of the character at position `l` and move `l` forward
16 cnt[int(s[l])] -= 1
17 l += 1
18
19 # Add the number of valid substrings ending at position `r`
20 ans += r - l + 1
21
22 # Return the total count of valid substrings
23 return ans
24
1class Solution {
2 public int countKConstraintSubstrings(String s, int k) {
3 // Array to count occurrences of '0' and '1'
4 int[] count = new int[2];
5
6 int answer = 0;
7 int left = 0;
8
9 // Loop through each character in the string
10 for (int right = 0; right < s.length(); ++right) {
11 // Increase count for the current character
12 ++count[s.charAt(right) - '0'];
13
14 // Check if both '0' and '1' counts exceed k
15 while (count[0] > k && count[1] > k) {
16 // Reduce count of the character at the left pointer
17 count[s.charAt(left++) - '0']--;
18 }
19
20 // Calculate the number of valid substrings ending at 'right'
21 answer += right - left + 1;
22 }
23
24 return answer; // Return total count of substrings
25 }
26}
27
1#include <string> // Include necessary headers for string operations
2
3class Solution {
4public:
5 int countKConstraintSubstrings(std::string s, int k) {
6 // Array to keep track of the count of '0's and '1's in the current window
7 int count[2] = {};
8 int answer = 0; // Variable to store the number of valid substrings
9 int left = 0; // Left pointer for the sliding window
10
11 // Iterate over the string with a right pointer
12 for (int right = 0; right < s.length(); ++right) {
13 // Increment the count of the current character in the window
14 count[s[right] - '0']++;
15
16 // Adjust the window to maintain the constraint of at most k '0's and '1's
17 while (count[0] > k && count[1] > k) {
18 // Decrement the count of the character at the left pointer
19 count[s[left++] - '0']--;
20 }
21
22 // Add the number of valid substrings ending at the current character
23 answer += right - left + 1;
24 }
25
26 return answer; // Return the total number of valid substrings
27 }
28};
29
1function countKConstraintSubstrings(s: string, k: number): number {
2 // This array keeps track of the counts of '0's and '1's in the current window.
3 const count: [number, number] = [0, 0];
4
5 // 'ans' will store the total number of valid substrings,
6 // and 'left' will mark the beginning of the sliding window.
7 let ans = 0;
8 let left = 0;
9
10 // Iterate over each character in the string using 'right' as the end of the sliding window.
11 for (let right = 0; right < s.length; ++right) {
12 // Increment the count of the current character ('0' or '1').
13 count[+s[right]]++;
14
15 // If both '0's and '1's counts exceed 'k', move the 'left'
16 // pointer to shrink the window until the condition is satisfied.
17 while (count[0] > k && count[1] > k) {
18 count[+s[left]]--;
19 left++;
20 }
21
22 // Add to 'ans' the number of new valid substrings ending at 'right'.
23 ans += right - left + 1;
24 }
25
26 return ans;
27}
28
Time and Space Complexity
The time complexity of the code is O(n)
, where n
is the length of the string s
. This is because the algorithm goes through each character of the string exactly once with two pointers l
and r
iterating over the string, achieving a linear time complexity.
The space complexity is O(1)
, as the algorithm uses a fixed amount of space regardless of the input size. The space usage includes a list cnt
with two elements to count occurrences of 0
and 1
, and a few integer variables for processing.
Learn more about how to find time and space complexity quickly.
Which data structure is used to implement recursion?
Recommended Readings
https algomonster s3 us east 2 amazonaws com cover_photos stack svg Sliding Window Maximum Monotonic Stack We have an array and a sliding window defined by a start index and an end index The sliding window moves from left of the array to right There are always k elements in
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https algomonster s3 us east 2 amazonaws com recursion jpg You first
Want a Structured Path to Master System Design Too? Don’t Miss This!