#include <bits/stdc++.h>
using namespace std;
using LL = long long;
constexpr int maxn = 1000000;
int f[maxn + 1];
char s[maxn + 2];
struct node {
  int maxv, minv, addv;
} t[maxn << 2];
void update(int v) {
  t[v].maxv = max(t[(v << 1)].maxv, t[(((v << 1)) | 1)].maxv);
  t[v].minv = min(t[(v << 1)].minv, t[(((v << 1)) | 1)].minv);
}
void add(int v, int x) {
  t[v].maxv += x;
  t[v].minv += x;
  t[v].addv += x;
}
void push_down(int v) {
  add((v << 1), t[v].addv);
  add((((v << 1)) | 1), t[v].addv);
  t[v].addv = 0;
}
void build(int v, int tl, int tr) {
  if (tl == tr)
    t[v].maxv = t[v].minv = f[((tl + tr) >> 1)];
  else {
    build((v << 1), tl, ((tl + tr) >> 1));
    build((((v << 1)) | 1), ((tl + tr) >> 1) + 1, tr);
    update(v);
  }
}
void update(int v, int tl, int tr, int L, int R) {
  if (tl >= L and tr <= R)
    add(v, 2);
  else {
    push_down(v);
    if (L <= ((tl + tr) >> 1)) update((v << 1), tl, ((tl + tr) >> 1), L, R);
    if (R > ((tl + tr) >> 1))
      update((((v << 1)) | 1), ((tl + tr) >> 1) + 1, tr, L, R);
    update(v);
  }
}
int query(int v, int tl, int tr, int L, int R) {
  if (tl >= L and tr <= R) return t[v].maxv;
  push_down(v);
  if (L > ((tl + tr) >> 1))
    return query((((v << 1)) | 1), ((tl + tr) >> 1) + 1, tr, L, R);
  if (R <= ((tl + tr) >> 1)) return query((v << 1), tl, ((tl + tr) >> 1), L, R);
  return max(query((v << 1), tl, ((tl + tr) >> 1), L, R),
             query((((v << 1)) | 1), ((tl + tr) >> 1) + 1, tr, L, R));
}
int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  cout.tie(nullptr);
  cin >> (s + 1);
  int n = strlen(s + 1);
  for (int i = 1; i <= n; i += 1) {
    f[i] = f[i - 1] - 1;
    if (s[i] == '1') f[i] += 2;
  }
  build(1, 0, n);
  int ans = t[1].maxv - t[1].minv;
  for (int i = 1; i <= n; i += 1)
    if (s[i] == '?') {
      int maxv = query(1, 0, n, i, n);
      if (maxv + 2 <= t[1].maxv) {
        update(1, 0, n, i, n);
        ans = min(ans, t[1].maxv - t[1].minv);
      }
    }
  cout << ans;
  return 0;
}
