#pragma GCC optimze("Ofast")
#include <bits/stdc++.h>
using namespace std;
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/rope>
using namespace __gnu_pbds;
using namespace __gnu_cxx;
#ifndef rd
#define trace(...)
#define endl '\n'
#endif
#define pb push_back
#define fi first
#define se second
//#define int long long
typedef long long ll;
typedef long double f80;
#define double long double
#define pii pair<int,int>
#define pll pair<ll,ll>
#define sz(x) ((long long)x.size())
#define fr(a,b,c) for(int a=b; a<=c; a++)
#define rep(a,b,c) for(int a=b; a<c; a++)
#define trav(a,x) for(auto &a:x)
#define all(con) con.begin(),con.end()
const ll infl=0x3f3f3f3f3f3f3f3fLL;
const int infi=0x3f3f3f3f;
//const int mod=998244353;
const int mod=1000000007;
typedef vector<int> vi;
typedef vector<ll> vl;

typedef tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> oset;
auto clk=clock();
mt19937_64 rang(chrono::high_resolution_clock::now().time_since_epoch().count());
int rng(int lim) {
	uniform_int_distribution<int> uid(0,lim-1);
	return uid(rang);
}
int powm(int a, int b) {
	int res=1;
	while(b) {
		if(b&1)
			res=(res*a)%mod;
		a=(a*a)%mod;
		b>>=1;
	}
	return res;
}


int pre[1000005];
const int N=1e6+5;
int tr[4*N],lazy[4*N];
void add(int seg, int ll, int rr, int l, int r, int val) {
	if(ll>r||l>rr)
		return;
	if(l<=ll&&rr<=r) {
		tr[seg]+=val;
		lazy[seg]+=val;
		return;
	}
	if(lazy[seg]) {
		tr[seg<<1]+=lazy[seg];
		tr[seg<<1|1]+=lazy[seg];
		lazy[seg<<1]+=lazy[seg];
		lazy[seg<<1|1]+=lazy[seg];
		lazy[seg]=0;
	}
	add(seg<<1,ll,(ll+rr)/2,l,r,val);
	add(seg<<1|1,1+(ll+rr)/2,rr,l,r,val);
	tr[seg]=max(tr[seg<<1],tr[seg<<1|1]);
}
int query(int seg, int ll, int rr, int p) {
	if(ll==p&&rr==p) {
		return tr[seg];
	}
	if((ll+rr)/2>=p)
		return query(seg<<1,ll,(ll+rr)/2,p);
	else
		return query(seg<<1|1,1+(ll+rr)/2,rr,p);
}
void solve() {
	string s;
	cin>>s;
	int n=sz(s);
	s='0'+s;
	set<int> q;
	vi lami;
	lami.pb(0);
	fr(i,1,n) {
		if(s[i]=='?') {
			q.insert(i);
			s[i]='0';
		}
		pre[i]=pre[i-1]+2*s[i]-'0'-'1';
		if(pre[i]<pre[lami.back()])
			lami.pb(i);
	}
	fr(i,0,n)
		add(1,0,n,i,i,pre[i]);
	if(lami.empty()) {
		cout<<*max_element(pre,pre+n+1)<<endl;
		return;
	}
	set<int> q2=q;
	vi lami2=lami;
	int ans=(*max_element(pre,pre+n+1))-(*min_element(pre+1, pre+n+1));
	for(int i=-n-1; i<=0; i+=2) {
		while(query(1,0,n,lami[sz(lami)-2])<i)
			lami.pop_back();
		if(query(1,0,n,lami.back())<i) {
			auto it=q2.upper_bound(lami.back());
			if(it==q2.begin()) {
				break;
			} else {
				it--;
				add(1,0,n,*it,n,+2);
				q2.erase(it);
			}
		}
		ans=min(ans,abs(i-tr[1]));
	}
	swap(lami,lami2);
	swap(q2,q);
	memset(tr,0,sizeof(tr));
	memset(lazy,0,sizeof(lazy));
	fr(i,0,n)
		add(1,0,n,i,i,pre[i]);
	for(int i=-n; i<=0; i+=2) {
		while(query(1,0,n,lami[sz(lami)-2])<i)
			lami.pop_back();
		if(query(1,0,n,lami.back())<i) {
			auto it=q2.upper_bound(lami.back());
			if(it==q2.begin()) {
				break;
			} else {
				it--;
				add(1,0,n,*it,n,+2);
				q2.erase(it);
			}
		}
		ans=min(ans,abs(i-tr[1]));
	}
	cout<<ans<<endl;
}

signed main() {
	ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	srand(chrono::high_resolution_clock::now().time_since_epoch().count());
	cout<<fixed<<setprecision(8);
	int t=1;
//	cin>>t;
	fr(i,1,t)
		solve();
#ifdef rd
	cout<<endl<<endl<<endl<<endl<<"Time elapsed: "<<(double)(clock()-clk)/CLOCKS_PER_SEC<<endl;
#endif
	return 0;
}
