Блог пользователя Shreyash1379

Автор Shreyash1379, история, 10 месяцев назад, По-английски

Problem Statement: Count Grouped Binary Substrings

In my last Post i gave the question to help people to solve the question and commented the code and its explanation if ever needed. But then, i think some of us really need a good explanation which i couldnt provide .So i am improving , providing better explanation, photos of the test case,etc for the community to get it in a better way with all my efforts.

Do upvote if you think the work i did was worth and you like it.

I found this problem during my JPMorgan Chase OA. It’s a good example of a string + grouping based DSA problem that tests your pattern observation.

You are given a binary string s consisting of only '0' and '1'.

A binary substring is called grouped if: - All '0's come together followed by all '1's, or - All '1's come together followed by all '0's.

For example, "0011" or "1100" are grouped, but "0101" is not.

You need to count the number of such non-empty substrings where: - The number of consecutive '0's and '1's are equal, and - All '0's and '1's are grouped together (e.g. "01", "0011", "1100", "000111", etc.)


Input

A binary string s of length up to 10^5.


Output

An integer denoting the total number of valid grouped substrings.


Example

Input:

00110011

Output:

6

Explanation

The valid grouped substrings are: - "0011"(twice) - "01" (twice) - "1100" - "10"

Total = 6.


Spoiler Ahead :)

Detailed Explanation and code are shared below

 !

Spoiler

Explanation:-

The code works as first: we group all the grouped 0's,1's, and then try to make pairs of them to get the number of strings, for example.

In 00110011

Let's say we would get nums as

2 2 2 2
i.e.2 '0',s 2 '1's 2 '0's 2 '1's so now i make the ans from this count as lets say the array of the count be nums.

So for two contiguous groups nums[0] and nums[1] i.e. 2 0's ans 2 1's can make atmost min(2,2)=2 i.e. two substrings which satisfy the condition i.e. 01 , 0011

for e.g. if we get something like 000011 so we can make min(4,2) =2 substrings 0011 01 .

Similarly, we can do it for all adjacent groups by making up to min(of the two adjacent)groups

I hope you would have understood the explanation plz upvote if you like and understand __

Code:-

// this is code

#include <bits/stdc++.h>
using namespace std;

void solve(){
  string s;
    cin>>s;
    int n=s.size();
    
    
    vector<int>nums;
    int i=0;
    
    while(i<n){
      i++;
      int cnt=1;
      while(i<n && i==0 || s[i]==s[i-1]){
        cnt++;
        i++;
      }
      nums.push_back(cnt);
    }
    
    
    int ans=0;
    for(int i=0;i<nums.size()-1;i++){
      ans+=min(nums[i],nums[i+1]);
    }
    
    cout<<ans<<"\n";
}

int main() 
{
  int t;
  cin>>t;
    for(int i=0;i<t;i++){
      solve();
    }
    return 0;
}
  • Проголосовать: нравится
  • -21
  • Проголосовать: не нравится

»
10 месяцев назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

Auto comment: topic has been updated by Shreyash1379 (previous revision, new revision, compare).

»
10 месяцев назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

Auto comment: topic has been updated by Shreyash1379 (previous revision, new revision, compare).

»
10 месяцев назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

Auto comment: topic has been updated by Shreyash1379 (previous revision, new revision, compare).

»
10 месяцев назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

Check out my solution.
I tried solving in 1 pass
Logic : we will count the number of countigous 0s before 1 , lets call it cnt0 and from the first index where we have found 1, we will ans++ if until the number of contigous 1s is less than cnt0.
Similar thing will be done in reverse case.

int solve(string &s){
	int n=s.size();
	int ans=0,cnt0=0,cnt1=0;
	for(int i=0;i<n;i++){
		if(s[i]=='0'){
			if(i!=0 and s[i-1]!='0')cnt0=0;
			cnt0++;
			if(cnt0<=cnt1)ans++;
		}else{
			if(i!=0 and s[i-1]!='1')cnt1=0;
			cnt1++;
			if(cnt1<=cnt0)ans++;
		}
	}
	return ans;
}
  • »
    »
    10 месяцев назад, скрыть # ^ |
    Rev. 2  
    Проголосовать: нравится 0 Проголосовать: не нравится

    OK got it you just did by keeping track of recents and updating them in the same loop instead of other. But at the time of OA it didn't matter for me to put it fronm 2n to n as it was the same.

    So I got to the next question. Still Great !!!

    I hope the community would like that.

    This is an amazing thing to work on. O(2n)->O(n);

    Something more to think---> Actually, you can do it bit differntly too as current and prev. where you just pass the current to prev and start appending current whenever the charachters are changed.

    Sort of same logic just different way of thinking.

    DO UPVOTE IF YOU THINK IT HELP YOU AND YOU LIKE IT

»
10 месяцев назад, скрыть # |
 
Проголосовать: нравится +9 Проголосовать: не нравится

Div2 A level problem

»
10 месяцев назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

Auto comment: topic has been updated by Shreyash1379 (previous revision, new revision, compare).

»
10 месяцев назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

Can we do it like whenever we find "01" or "10" then we try to expand from this position by assuming l = i, r = i + 1 and we will do l--, r++ till we can match means make the valid substring. At first glance think approach looks like O(N^2) but i think we will not go to any position more than 3 times ?? Please correct me if i am wrong

#include <bits/stdc++.h>
using namespace std;

#define int long long
#define ARUN std::ios::sync_with_stdio(false);std::cin.tie(nullptr);

int32_t main() {
    ARUN;
    /* code here */
    string s; cin >> s;
    int n = s.size();

    int ans = 0;
    for (int i = 1; i < n; i++) {
        int l = i - 1, r = i;
        if (((s[l] - '0') ^ (s[r] - '0')) == 0) continue;
        // now we have either '01' or '10'
        // try to expand 
        int len = 2;
        while (l - 1 >= 0 && r + 1 < n && s[l - 1] == s[l] && s[r] == s[r + 1]) {
            len += 2;
            --l, ++r;
        }
        // we can choose any position from len/2 position from start and end of the substring 
        ans += len / 2;
    }
    cout << ans << endl;
    return 0;
}
  • »
    »
    10 месяцев назад, скрыть # ^ |
    Rev. 2  
    Проголосовать: нравится 0 Проголосовать: не нравится

    Ya you are correct its a O(n) approach .

    As the r increments it would it increment as much as the i needs to be put up at the next,also in n^2 elements are revisited.Here it wouldnt happen on the r side to be true.It would happen on left but since its happening simulatneously with right side we can say its not revisiting. and moving further

    Great observation.

»
9 месяцев назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

Check this one

#include<bits/stdc++.h>
using namespace std;

int countSubstring(string &s) {
    if(s.size() < 2) return 0;

    int cnt=0;
    int prev=0, curr=1;
    for(int i=1; i<s.size();++i) {
        if(s[i]==s[i-1]){
            curr++;
        }else{
            cnt+=min(prev, curr);
            prev=curr;
            curr=1;//reset
        }
    }
    cnt+=min(prev, curr); //for last part
    return cnt;
}

int main() {
    string ip="01010101";
    cout<<"input string is : "<<ip<<endl;
    cout<<"output is : "<<countSubstring(ip)<<endl;
    return 0;
}