#include <bits/stdc++.h>
using namespace std;
using ll = long long;
template <typename M>
class segment_tree {
 private:
  size_t size_;
  std::vector<M> tree_;

 public:
  explicit segment_tree(size_t size) : size_(size), tree_(size * 2) {}
  template <typename Iter>
  explicit segment_tree(Iter begin, Iter end) : segment_tree(end - begin) {
    for (auto it = begin; it != end; ++it) tree_[size_ + it - begin] = *it;
    for (size_t i = size_ - 1; i > 0; i--)
      tree_[i] = tree_[i * 2] * tree_[i * 2 + 1];
  }
  M operator[](size_t index) const { return tree_[size_ + index]; }
  void set(size_t index, M val) {
    auto i = size_ + index;
    tree_[i] = val;
    i >>= 1;
    while (i > 0) {
      tree_[i] = tree_[i * 2] * tree_[i * 2 + 1];
      i >>= 1;
    }
  }
  M query(size_t l, size_t r) const {
    M lhs, rhs;
    for (auto _l = l + size_, _r = r + size_; _l < _r; _l >>= 1, _r >>= 1) {
      if (_l & 1) lhs = lhs * tree_[_l++];
      if (_r & 1) rhs = tree_[--_r] * rhs;
    }
    return lhs * rhs;
  }
};
int main() {
  cin.tie(nullptr);
  ios::sync_with_stdio(false);
  string s;
  cin >> s;
  if (s.size() == 1) {
    cout << 1 << endl;
  } else {
    bool real = true;
    vector<int> ds;
    for (int i = 0; i < s.size(); i++) {
      if (i == 0 or real != (s[i] != '?')) {
        ds.push_back(i);
      }
      real = s[i] != '?';
    }
    ds.push_back(s.size());
    struct Bits {
      int cnt, minc, maxc;
    };
    vector<Bits> bs;
    vector<int> vs;
    for (int i = 0; i < ds.size() - 1; i++) {
      auto f = ds[i];
      auto t = ds[i + 1];
      if (s[f] != '?') {
        int cnt = 0;
        int minc = 0;
        int maxc = 0;
        for (int j = f; j < t; j++) {
          cnt += (s[j] == '1' ? 1 : -1);
          minc = min(minc, cnt);
          maxc = max(maxc, cnt);
        }
        bs.push_back({cnt, minc, maxc});
      } else {
        vs.push_back(t - f);
      }
    }
    int vfront = 0;
    if (s[0] == '?') {
      vfront = vs[0];
      vs.erase(vs.begin());
    }
    struct Max {
      int x;
      Max(int x = -1e9) : x(x) {}
      Max operator*(const Max& r) const { return {max(x, r.x)}; }
      Max& operator*=(const Max& r) { return *this = *this * r; }
    };
    segment_tree<Max> rmq(bs.size());
    auto max_floor = [&](int max_top) {
      int floor = 0;
      int r = vfront;
      int up = 0;
      int c = -vfront;
      for (int i = 0; i < bs.size(); i++) {
        auto buf = max_top - rmq.query(i, bs.size()).x - up;
        buf = min(r * 2 - up, buf);
        buf -= buf & 1;
        up += buf;
        c += buf;
        floor = min(floor, c + bs[i].minc);
        c += bs[i].cnt;
        if (i < vs.size()) {
          r += vs[i];
          c -= vs[i];
        }
      }
      return floor;
    };
    int min_top = 0, min_bottom = 0;
    int c = -vfront;
    for (int i = 0; i < bs.size(); i++) {
      min_top = max(min_top, c + bs[i].maxc);
      rmq.set(i, c + bs[i].maxc);
      min_bottom = min(min_bottom, c + bs[i].minc);
      c += bs[i].cnt;
      if (i < vs.size()) c -= vs[i];
    }
    auto ans =
        min(min_top - max_floor(min_top), min_top + 1 - max_floor(min_top + 1));
    cout << ans << endl;
  }
  return 0;
}
