Taro Logo

Count Substrings That Satisfy K-Constraint I

#799 Most AskedEasy
21 views
Topics:
StringsTwo PointersSliding Windows

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 most k.
  • The number of 1's in the string is at most k.

Return an integer denoting the number of substrings of s that satisfy the k-constraint.

Example 1:

Input: s = "10101", k = 1

Output: 12

Explanation:

Every substring of s except the substrings "1010", "10101", and "0101" satisfies the k-constraint.

Example 2:

Input: s = "1010101", k = 2

Output: 25

Explanation:

Every substring of s except the substrings with a length greater than 5 satisfies the k-constraint.

Example 3:

Input: s = "11111", k = 1

Output: 15

Explanation:

All substrings of s satisfy the k-constraint.

Constraints:

  • 1 <= s.length <= 50
  • 1 <= k <= s.length
  • s[i] is either '0' or '1'.

Solution


Clarifying Questions

When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:

  1. What is the allowable range for the value of 'K'? Can 'K' be zero or negative?
  2. What characters can the input string contain? Is it limited to lowercase English letters, or are uppercase letters, numbers, or special characters possible?
  3. If no substrings satisfy the K-constraint, what should be returned? Should I return 0, -1, or some other specific value?
  4. Could you clarify what constitutes a 'substring' for the purpose of this problem? Are we looking for contiguous sequences of characters only?
  5. What is the maximum length of the input string? Are there any memory constraints that I should consider given the potential number of substrings?

Brute Force Solution

Approach

The brute force method tackles this problem by checking every possible substring within the given text. For each substring, it evaluates if it adheres to the constraint involving the number of distinct characters. Finally, we count all the substrings that satisfy the condition.

Here's how the algorithm would work step-by-step:

  1. Consider the beginning of the text as the start of a potential valid substring.
  2. Starting from this beginning, grow the substring one character at a time.
  3. For each grown substring, count the number of different characters it contains.
  4. Check if this count meets our given constraint (the 'K' value).
  5. If the constraint is met, we mark this substring as valid.
  6. Repeat this growing and checking process until we reach the end of the text.
  7. Now, move the beginning of the potential substring one character forward and repeat the entire process.
  8. Continue moving the beginning forward and re-running the process until it reaches near the end of the original text. We should now have checked every possible substring.
  9. Finally, we count all the substrings we marked as valid to get our answer.

Code Implementation

def count_substrings_that_satisfy_k_constraint_i(text, k_value):
    number_of_valid_substrings = 0
    text_length = len(text)

    for left_index in range(text_length):
        for right_index in range(left_index, text_length):
            substring = text[left_index : right_index+1]
            # Counting distinct chars in the current substring
            distinct_characters = set(substring)

            # Only increment if the constraint is met
            if len(distinct_characters) == k_value:
                number_of_valid_substrings += 1

    return number_of_valid_substrings

Big(O) Analysis

Time Complexity
O(n³) – The algorithm iterates through all possible substrings of the input string of length n. The outer loop determines the starting position of the substring, which runs n times. The inner loop expands the substring from the starting position to the end of the string, also running up to n times. Inside the inner loop, the number of distinct characters in the substring needs to be calculated which takes up to n operations in the worst case. Therefore, the overall time complexity is approximately n * n * n, which simplifies to O(n³).
Space Complexity
O(1) – The provided brute force approach iterates through all possible substrings. For each substring, it counts the number of distinct characters. This count can be performed using a fixed-size character frequency table or a similar structure that holds a constant number of character counts (e.g., a boolean array of size 26 for lowercase English letters). The algorithm uses a fixed number of integer variables and this constant-sized character counting structure. Thus, the auxiliary space used is independent of the input string's length, N, resulting in constant space complexity.

Optimal Solution

Approach

The key to efficiently counting substrings with a K-constraint is to avoid recomputing information. We use a sliding window that expands to include more characters, and shrinks from the left when the K-constraint is violated, reusing information about the substring inside the window.

Here's how the algorithm would work step-by-step:

  1. Imagine a window that slides across the string, showing a part of it at a time.
  2. Start with an empty window at the beginning of the string.
  3. Expand the window by adding one character to the right.
  4. Check if the substring inside the window satisfies the K-constraint. If it does, increase a counter.
  5. If the window does not satisfy the constraint, shrink the window by removing characters from the left until it does satisfy the constraint or becomes empty.
  6. Keep expanding and shrinking the window while tracking how many times you satisfy the K-constraint at a given point. Keep accumulating the count.
  7. Repeat the process of sliding the window to the right across the entire string.

Code Implementation

def count_substrings_with_k_constraint(input_string, max_k_value):
    string_length = len(input_string)
    substring_count = 0
    left_pointer = 0
    current_unique_count = 0
    character_frequency = {}

    for right_pointer in range(string_length):
        right_character = input_string[right_pointer]

        if right_character not in character_frequency:
            character_frequency[right_character] = 0

        if character_frequency[right_character] == 0:
            current_unique_count += 1

        character_frequency[right_character] += 1

        # Shrink the window if unique character count exceeds constraint
        while current_unique_count > max_k_value:
            left_character = input_string[left_pointer]
            character_frequency[left_character] -= 1

            if character_frequency[left_character] == 0:
                current_unique_count -= 1

            left_pointer += 1

        # Accumulate the count of valid substrings
        substring_count += right_pointer - left_pointer + 1

    return substring_count

Big(O) Analysis

Time Complexity
O(n) – The algorithm uses a sliding window approach to iterate through the string of length n. The outer loop expands the window by adding characters to the right, iterating through the entire string once. The inner loop shrinks the window from the left only when the K-constraint is violated. Each character is added and removed from the window at most once. Therefore, even though there is a nested while loop, the overall time complexity is linear, O(n), because the total number of operations performed by both loops is proportional to the length of the string.
Space Complexity
O(1) – The algorithm uses a sliding window approach. Although the plain English explanation alludes to 'keeping track' and 'accumulating', it doesn't explicitly mention creating additional data structures that scale with the input string's length, N. The sliding window operations likely involve only a few variables to maintain the window's boundaries and to check for the K-constraint, leading to constant auxiliary space. Therefore, the space complexity remains constant, regardless of the size of the input string.

Edge Cases

Empty string input
How to Handle:
Return 0 as there are no substrings to count if the input string is empty.
k is zero
How to Handle:
If k is 0, count substrings that contain the same character.
String with all same characters and k = 1
How to Handle:
Return n*(n+1)/2, where n is the length of the string, as any substring satisfies the constraint.
String containing only one character and k > 1
How to Handle:
Return 0 because no substring will contain more than one distinct character.
Maximum length string (e.g., length 100000) with large k
How to Handle:
Ensure the sliding window approach is optimized to avoid excessive computations and consider data structure memory usage.
String with unicode characters.
How to Handle:
Ensure the code handles unicode characters correctly, considering their possible multi-byte representations.
k is negative
How to Handle:
Return 0 or throw an IllegalArgumentException, depending on whether negative k is considered a valid input.
Integer overflow when calculating the count of substrings for long strings.
How to Handle:
Use long data type or alternative data structures to prevent integer overflow issues.
0/1916 completed