//teja349
#include <bits/stdc++.h>
#include <vector>
#include <set>
#include <map>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <climits>
#include <utility>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <iomanip>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp> 
//setbase - cout << setbase (16); cout << 100 << endl; Prints 64
//setfill -   cout << setfill ('x') << setw (5); cout << 77 << endl; prints xxx77
//setprecision - cout << setprecision (14) << f << endl; Prints x.xxxx
//cout.precision(x)  cout<<fixed<<val;  // prints x digits after decimal in val

using namespace std;
using namespace __gnu_pbds;

#define f(i,a,b) for(i=a;i<b;i++)
#define rep(i,n) f(i,0,n)
#define fd(i,a,b) for(i=a;i>=b;i--)
#define pb push_back
#define mp make_pair
#define vi vector< int >
#define vl vector< ll >
#define ss second
#define ff first
#define ll long long
#define pii pair< int,int >
#define pll pair< ll,ll >
#define sz(a) a.size()
#define inf (1000*1000*1000+5)
#define all(a) a.begin(),a.end()
#define tri pair<int,pii>
#define vii vector<pii>
#define vll vector<pll>
#define viii vector<tri>
#define mod (1000*1000*1000+7)
#define pqueue priority_queue< int >
#define pdqueue priority_queue< int,vi ,greater< int > >
#define flush fflush(stdout) 
#define primeDEN 727999983
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

// find_by_order()  // order_of_key
typedef tree<
int,
null_type,
less<int>,
rb_tree_tag,
tree_order_statistics_node_update>
ordered_set;

struct tot{
	int minval;
	//int minpos;
	int maxval;
	int maxpos;
};
tot seg[4123456];
int lazy[4123456];	
int pre[4123456],a[4123456];
int build(int node,int s,int e){
	lazy[node]=0;
	if(s==e){
		seg[node].minval=pre[s];
		seg[node].maxval=pre[s];
		seg[node].maxpos=s;
		return 0;
	}
	int mid=(s+e)/2;
	build(2*node,s,mid);
	build(2*node+1,mid+1,e);
	seg[node].minval=min(seg[2*node].minval,seg[2*node+1].minval);
	seg[node].maxval=max(seg[2*node].maxval,seg[2*node+1].maxval);
	if(seg[node].maxval == seg[2*node].maxval){
		seg[node].maxpos = seg[2*node].maxpos;
	}
	else{
		seg[node].maxpos = seg[2*node+1].maxpos;
	}
	return 0;
}

int update(int node,int s,int e,int l,int r){
	if(lazy[node]){
		seg[node].maxval+=lazy[node];
		seg[node].minval+=lazy[node];
		if(s!=e){
			lazy[2*node]+=lazy[node];
			lazy[2*node+1]+=lazy[node];
		}
		lazy[node]=0;
	}
	if(e<l || r<s){
		return 0;
	}
	if(l<=s && e<=r){
		lazy[node]=-2;
		seg[node].maxval+=lazy[node];
		seg[node].minval+=lazy[node];
		if(s!=e){
			lazy[2*node]+=lazy[node];
			lazy[2*node+1]+=lazy[node];
		}
		lazy[node]=0;
		return 0;
	}
	int mid = (s+e)/2;
	update(2*node,s,mid,l,r);
	update(2*node+1,mid+1,e,l,r);
	seg[node].minval=min(seg[2*node].minval,seg[2*node+1].minval);
	seg[node].maxval=max(seg[2*node].maxval,seg[2*node+1].maxval);
	if(seg[node].maxval == seg[2*node].maxval){
		seg[node].maxpos = seg[2*node].maxpos;
	}
	else{
		seg[node].maxpos = seg[2*node+1].maxpos;
	}
	return 0;
}

int sufmin[4123456];
int main(){
    std::ios::sync_with_stdio(false); cin.tie(NULL);
    string s;
    cin>>s;
    int i;
    int n=s.length();
    set<int> seti;
    f(i,1,n+1){
    	if(s[i-1]=='0'){
    		a[i]=-1;
    	}
    	else if(s[i-1]=='1'){
    		a[i]=1;
    	}
    	else{
    		a[i]=1;
    		seti.insert(i);
    	}
    	pre[i]=pre[i-1]+a[i];
    }
    build(1,0,n);
    sufmin[n+1]=inf;
    fd(i,n,0){
    	sufmin[i]=min(sufmin[i+1],pre[i]);
    }
    int ans=inf;
    int cur=n+10,pos=n;
    set<int>::iterator it;
    while(!seti.empty()){
    	while(pos>=0 && sufmin[pos]>=cur+2){
    		pos--;
    	}
    	cur-=2;
    	it=seti.upper_bound(pos);
    	if(it==seti.end()){
    		continue;
    	}
    	int vali=*it;
    	//cout<<vali<<" "<<cur<<" "<<pos<<endl;
    	seti.erase(vali);
    	update(1,0,n,vali,n);
    	int mini = seg[1].minval;
    	int maxi = seg[1].maxval;
    	ans=min(ans,maxi-mini);
    }
    f(i,1,n+1){
    	if(s[i-1]=='0'){
    		a[i]=-1;
    	}
    	else if(s[i-1]=='1'){
    		a[i]=1;
    	}
    	else{
    		a[i]=1;
    		seti.insert(i);
    	}
    	pre[i]=pre[i-1]+a[i];
    }
    build(1,0,n);
    cur=n+9;
    pos=n;
    while(!seti.empty()){
    	while(pos>=0 && sufmin[pos]>=cur+2){
    		pos--;
    	}
    	cur-=2;
    	it=seti.upper_bound(pos);
    	if(it==seti.end()){
    		continue;
    	}
    	int vali=*it;
    	seti.erase(vali);
    	update(1,0,n,vali,n);
    	int mini = seg[1].minval;
    	int maxi = seg[1].maxval;
    	ans=min(ans,maxi-mini);
    }
    cout<<ans<<endl;
    return 0;   
}
