#include <bits/stdc++.h>
using namespace std;
template <class T, class E>
struct RangeUpdateLinearAmplifySegmentTree {
  T aggregation(T x, T y) {
    return pair<long long, long long>(x.first + y.first,
                                      min(x.second, y.second));
  }
  T apply(E e, T t) {
    return pair<long long, long long>(t.first + e.first,
                                      min(t.second, t.first + e.second));
  }
  E merge(E x, E y) {
    return pair<long long, long long>(x.first + y.first,
                                      min(x.second, x.first + y.second));
  }
  E amplify(int x, E e) {
    return pair<long long, long long>(x * e.first, x * e.second);
  }
  T default_element() { return pair<long long, long long>(0, 0); }
  E default_operator() { return pair<long long, long long>(0, 0); }
  int offset;
  vector<T> buffer;
  vector<E> operator_buffer;
  RangeUpdateLinearAmplifySegmentTree(const vector<T>& initial_values) {
    const int n = initial_values.size();
    int row_length = 1;
    while (n > row_length) {
      row_length *= 2;
    }
    offset = row_length - 1;
    buffer = vector<T>(row_length * 2, default_element());
    operator_buffer = vector<E>(row_length * 2, default_operator());
    for (int i = 0; i < n; ++i) {
      buffer[offset + i] = initial_values[i];
    }
    initialize_buffer();
  }
  void initialize_buffer() {
    for (int i = offset - 1; i >= 0; --i) {
      buffer[i] = aggregation(buffer[2 * i + 1], buffer[2 * i + 2]);
    }
  }
  void propagate(int length, int i) {
    if (operator_buffer[i] == default_operator()) {
      return;
    }
    if (i * 2 + 2 < operator_buffer.size()) {
      operator_buffer[i * 2 + 1] =
          merge(operator_buffer[i * 2 + 1], operator_buffer[i]);
      operator_buffer[i * 2 + 2] =
          merge(operator_buffer[i * 2 + 2], operator_buffer[i]);
    }
    buffer[i] = apply(amplify(length, operator_buffer[i]), buffer[i]);
    operator_buffer[i] = default_operator();
  }
  T aggregate(int l, int r) {
    return aggregate_recursive(l, r, 0, 0, offset + 1);
  }
  T aggregate_recursive(int l, int r, int i, int p, int q) {
    propagate(q - p, i);
    if (q <= l || r <= p) {
      return default_element();
    }
    if (l <= p && q <= r) {
      return buffer[i];
    }
    const int left = 2 * i + 1;
    const int right = left + 1;
    const int m = (p + q) / 2;
    return aggregation(aggregate_recursive(l, r, left, p, m),
                       aggregate_recursive(l, r, right, m, q));
  }
  void update(int l, int r, E x) {
    update_recursive(l, r, x, 0, 0, offset + 1);
  }
  T update_recursive(int l, int r, E x, int i, int p, int q) {
    propagate(q - p, i);
    if (q <= l || r <= p) {
      return buffer[i];
    }
    if (l <= p && q <= r) {
      operator_buffer[i] = merge(operator_buffer[i], x);
      return apply(amplify(q - p, operator_buffer[i]), buffer[i]);
    }
    const int left = 2 * i + 1;
    const int right = left + 1;
    const int m = (p + q) / 2;
    return buffer[i] = aggregation(update_recursive(l, r, x, left, p, m),
                                   update_recursive(l, r, x, right, m, q));
  }
  T get_at(int i) { return aggregate(i, i + 1); }
};
int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);
  string s;
  cin >> s;
  const long long tree_size = (s.size() + 1) / 2 + 1;
  vector<pair<long long, long long> > even_init_values(tree_size),
      odd_init_values(tree_size);
  for (int i = 0; i < tree_size; ++i) {
    even_init_values[i] = make_pair(-i * 2, -i * 2);
    odd_init_values[i] = make_pair(-i * 2 - 1, -i * 2 - 1);
  }
  RangeUpdateLinearAmplifySegmentTree<pair<long long, long long>,
                                      pair<long long, long long> >
      even_tree(even_init_values), odd_tree(odd_init_values);
  long long min_maximum = 0, cur = 0;
  vector<long long> min_offset(1, 0);
  for (int i = 0; i < s.size(); ++i) {
    if (s[i] == '1') {
      cur += 1;
    } else {
      cur -= 1;
    }
    min_offset.emplace_back(cur);
    min_maximum = max(cur, min_maximum);
  }
  vector<long long> back_max(s.size() + 1, min_offset.back());
  for (int i = s.size() - 1; i >= 0; --i) {
    back_max[i] = max(back_max[i + 1], min_offset[i]);
  }
  const long long even_min_index = (min_maximum + 1) / 2;
  const long long odd_min_index = min_maximum / 2;
  for (int i = 0; i < s.size(); ++i) {
    if (s[i] == '0') {
      even_tree.update(even_min_index, tree_size, make_pair(-1, -1));
      odd_tree.update(odd_min_index, tree_size, make_pair(-1, -1));
    } else if (s[i] == '1') {
      even_tree.update(even_min_index, tree_size, make_pair(1, 1));
      odd_tree.update(odd_min_index, tree_size, make_pair(1, 1));
    } else {
      {
        long long p = even_min_index - 1, q = tree_size;
        while (q - p > 1) {
          long long m = (p + q) / 2;
          if (even_tree.get_at(m).first + 1 +
                  max(0LL, back_max[i + 1] - min_offset[i + 1]) >
              0) {
            p = m;
          } else {
            q = m;
          }
        }
        even_tree.update(even_min_index, q, make_pair(-1, -1));
        even_tree.update(q, tree_size, make_pair(1, 1));
      }
      {
        long long p = odd_min_index - 1, q = tree_size;
        while (q - p > 1) {
          long long m = (p + q) / 2;
          if (odd_tree.get_at(m).first + 1 +
                  max(0LL, back_max[i + 1] - min_offset[i + 1]) >
              0) {
            p = m;
          } else {
            q = m;
          }
        }
        odd_tree.update(odd_min_index, q, make_pair(-1, -1));
        odd_tree.update(q, tree_size, make_pair(1, 1));
      }
    }
  }
  long long ans = s.size();
  for (int i = 0; i < tree_size; ++i) {
    if (i >= even_min_index) {
      ans = min(ans, -even_tree.get_at(i).second);
    }
    if (i >= odd_min_index) {
      ans = min(ans, -odd_tree.get_at(i).second);
    }
  }
  cout << ans << endl;
  return 0;
}
