Open In App

Counting Good Substrings with 0s, 1s, and ?s

Last Updated : 09 Jan, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

Given a string S consisting of characters 0,1,? A string is called good if all the adjacent characters in it are different i.e. of the form 0101010… or 1010101… You can replace ? with 0 or 1. Your task is to determine the number of good contiguous substrings of the string S.

Constraint: |S|<200000;

Example:

Input: S=0?10
Output: 8

Input: S = ???
Output: 6

Approach:

The idea is to uses dynamic programming to efficiently count the number of good contiguous substrings in a given string. It maintains a 2D array lst to store the last occurrences of ‘0’ and ‘1’ at even and odd positions separately. The main loop iterates through each character in the string, updating the index j based on the last occurrences and calculating the number of good substrings by adding the difference between the current index and j to the answer. Our would algorithm considers the patterns ’01’ and ’10’, treating ‘?’ as a wildcard. The last occurrences of ‘0’ and ‘1’ are updated for each character, and the final answer is returned.

Step-by-step approach:

  • Initialize a 2D vector to store the last occurrence indices of ‘0’ and ‘1’
  • Initialize a variable ans to store the answer
  • Iterate through each character in the string
    • Determine the parity of the current index (0 or 1)
    • Update j based on the last occurrences of ‘0’ and ‘1’ in the previous parity positions
    • Update the answer by adding the difference between the current index and j (i.e, ans += i – j).
    • Update the last occurrence indices for the current character
  • Return the answer (ans).

Below is the implementation of the above approach:

C++




#include <bits/stdc++.h>
using namespace std;
 
int solve(string& s)
{
    // Initialize a 2D vector to store the last occurrence
    // indices of '0' and '1'
    vector<vector<int> > dp(2, vector<int>(2, -1));
 
    // Initialize a variable to store the answer
    long long ans = 0;
 
    // Iterate through each character in the string
    for (int i = 0; i < int(s.size()); ++i) {
        int j = i - 1; // Initialize j to the previous index
 
        // Determine the parity of the current index (0 or
        // 1)
        int p = i & 1;
 
        // Update j based on the last occurrences of '0' and
        // '1' in the previous parity positions
        if (s[i] != '1')
            j = min(j, max(dp[0][p ^ 1], dp[1][p]));
        if (s[i] != '0')
            j = min(j, max(dp[0][p], dp[1][p ^ 1]));
 
        // Update the answer by adding the difference
        // between the current index and j
        ans += i - j;
 
        // Update the last occurrence indices for the
        // current character
        if (s[i] != '?')
            dp[s[i] - '0'][p] = i;
    }
 
    // Output the answer for the current test case
    return ans;
}
 
int main()
{
 
    // Input string
    string s = "0?10";
 
    int result = solve(s);
 
    cout << result;
 
    return 0;
}


Java




import java.util.Arrays;
 
public class Main {
 
    public static long solve(String s) {
        // Initialize a 2D array to store the last occurrence
        // indices of '0' and '1'
        int[][] dp = new int[2][2];
        for (int[] row : dp) {
            Arrays.fill(row, -1);
        }
 
        // Initialize a variable to store the answer
        long ans = 0;
 
        // Iterate through each character in the string
        for (int i = 0; i < s.length(); ++i) {
            int j = i - 1; // Initialize j to the previous index
 
            // Determine the parity of the current index (0 or 1)
            int p = i & 1;
 
            // Update j based on the last occurrences of '0' and
            // '1' in the previous parity positions
            if (s.charAt(i) != '1') {
                j = Math.min(j, Math.max(dp[0][p ^ 1], dp[1][p]));
            }
            if (s.charAt(i) != '0') {
                j = Math.min(j, Math.max(dp[0][p], dp[1][p ^ 1]));
            }
 
            // Update the answer by adding the difference
            // between the current index and j
            ans += i - j;
 
            // Update the last occurrence indices for the
            // current character
            if (s.charAt(i) != '?') {
                dp[s.charAt(i) - '0'][p] = i;
            }
        }
 
        // Output the answer for the current test case
        return ans;
    }
 
    public static void main(String[] args) {
        // Input string
        String s = "0?10";
 
        long result = solve(s);
 
        System.out.println(result);
    }
}
 
// This code is contributed by shivamgupta0987654321


Python3




def GFG(s):
    # Initialize a 2D array to store the last occurrence
    dp = [[-1, -1] for _ in range(2)]
    # Initialize a variable to store the answer
    ans = 0
     
    # Iterate through each character in the string
    for i in range(len(s)):
        j = i - 1
        # Determine the parity of the current index (0 or 1)
        p = i % 2
         
        # Check if the current character is not '1'
        if s[i] != '1':
            j = min(j, max(dp[0][p ^ 1], dp[1][p]))
         
        # Check if the current character is not '0'
        if s[i] != '0':
            j = min(j, max(dp[0][p], dp[1][p ^ 1]))
         
        # Update the answer by adding the difference
        # between the current index and j
        ans += i - j
         
        # Update the last occurrence indices for the current character
        if s[i] != '?':
            dp[int(s[i])][p] = i
     
    # Output the answer for the current test case
    return ans
 
# Input string
s = "0?10"
result = GFG(s)
print(result)


C#




using System;
 
class Program
{
    static long Solve(string s)
    {
        // Initialize a 2D array to store the last occurrence
        // indices of '0' and '1'
        int[,] dp = new int[2, 2] { { -1, -1 }, { -1, -1 } };
 
        // Initialize a variable to store the answer
        long ans = 0;
 
        // Iterate through each character in the string
        for (int i = 0; i < s.Length; ++i)
        {
            int j = i - 1; // Initialize j to the previous index
 
            // Determine the parity of the current index (0 or 1)
            int p = i % 2;
 
            // Update j based on the last occurrences of '0' and
            // '1' in the previous parity positions
            if (s[i] != '1')
                j = Math.Min(j, Math.Max(dp[0, p ^ 1], dp[1, p]));
            if (s[i] != '0')
                j = Math.Min(j, Math.Max(dp[0, p], dp[1, p ^ 1]));
 
            // Update the answer by adding the difference
            // between the current index and j
            ans += i - j;
 
            // Update the last occurrence indices for the
            // current character
            if (s[i] != '?')
                dp[s[i] - '0', p] = i;
        }
 
        // Output the answer for the current test case
        return ans;
    }
 
    static void Main()
    {
        // Input string
        string s = "0?10";
 
        long result = Solve(s);
 
        Console.WriteLine(result);
    }
}


Javascript




function GFG(s) {
    // Initialize a 2D array to the store the last occurrence
    let dp = Array.from({ length: 2 }, () => Array(2).fill(-1));
    // Initialize a variable to store the answer
    let ans = 0;
    // Iterate through each character in the string
    for (let i = 0; i < s.length; ++i) {
        let j = i - 1;
        // Determine the parity of the current index (0 or 1)
        let p = i % 2;
        if (s[i] !== '1') {
            j = Math.min(j, Math.max(dp[0][p ^ 1], dp[1][p]));
        }
        if (s[i] !== '0') {
            j = Math.min(j, Math.max(dp[0][p], dp[1][p ^ 1]));
        }
        // Update the answer by adding the difference
        // between current index and j
        ans += i - j;
        // Update the last occurrence indices for the current character
        if (s[i] !== '?') {
            dp[parseInt(s[i])][p] = i;
        }
    }
    // Output the answer for the current test case
    return ans;
}
// Input string
let s = "0?10";
let result = GFG(s);
console.log(result);


Output

8







Time complexity: O(N)
Auxiliary Space: O(1)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads