#include <bits/stdc++.h>
#pragma GCC optimize(3)
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("Ofast,no-stack-protector")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC target("sse,sse2,sse3,sse3,sse4,popcnt,abm,mmx")
#pragma GCC target("avx")
using namespace std;
struct IN {
} in;
inline bool delim(char& c) { return c == ' ' || c == '\n' || c == '\r'; }
template <typename T>
inline IN& operator>>(IN& t, T& a) {
  char buf;
  a = 0;
  while (delim(buf = getchar()))
    ;
  if (buf == '-') {
    t >> a;
    a = -a;
    return t;
  }
  while (true) {
    a *= 10;
    a += buf - '0';
    if (delim(buf = getchar())) break;
  }
  return t;
}
inline IN& operator>>(IN& t, std::string& s) {
  char buf;
  s.clear();
  while (delim(buf = getchar()))
    ;
  do {
    s += buf;
  } while (!delim(buf = getchar()));
  return t;
}
inline IN& operator>>(IN& t, char& c) {
  while (delim(c = getchar()))
    ;
  return t;
}
const int32_t N = 2 * (1e6) + 6;
const int32_t MOD = (1e9) + 7;
int32_t lft[N], rgh[N], del[N];
vector<int32_t> l, r;
int32_t main() {
  ios_base::sync_with_stdio();
  cout.tie(0);
  string s;
  in >> s;
  int32_t ans = 0, n = s.size();
  for (int32_t i(1); i < n; i++) {
    if (s[i - 1] != s[i]) {
      l.push_back(i - 1);
      r.push_back(i);
    }
  }
  for (int32_t i(0); i < l.size(); i++) {
    lft[i] = i - 1;
    rgh[i] = i + 1;
  }
  lft[l.size()] = n + 5;
  rgh[l.size()] = n + 5;
  del[l.size()] = 1;
  int32_t f = 0, rhave = n, lhave = 0;
  while (f == 0) {
    f = 1;
    for (int32_t i(0); i < l.size(); i++) {
      if (del[i] == 0) {
        if (s[l[i]] != s[r[i]]) {
          l[i]--, r[i]++;
          f = 0;
        } else {
          if (lft[i] >= 0 && rgh[i] < l.size()) {
            if (lft[i] > -1) rgh[lft[i]] = rgh[i];
            if (rgh[i] < l.size()) lft[rgh[i]] = lft[i];
          }
          del[i] = 1;
        }
      }
    }
    if (f == 0) ans++;
    for (int32_t i(0); i < l.size(); i++) {
      if (del[i] == 1) continue;
      if (l[i] < lhave || r[i] >= rhave) {
        del[i] = 1;
        if (l[i] < lhave) lhave = r[i];
        if (r[i] >= rhave) rhave = l[i];
      }
      if (lft[i] >= 0 && del[lft[i]] == 0 && l[i] < r[lft[i]]) {
        del[i] = 1;
        if (lft[i] > -1) rgh[lft[i]] = rgh[i];
        if (rgh[i] < l.size()) lft[rgh[i]] = lft[i];
        r[lft[i]] = r[i];
        continue;
      }
      if (rgh[i] >= 0 && del[rgh[i]] == 0 && r[i] > l[rgh[i]]) {
        del[i] = 1;
        if (lft[i] > -1) rgh[lft[i]] = rgh[i];
        if (rgh[i] < l.size()) lft[rgh[i]] = lft[i];
        l[rgh[i]] = l[i];
        continue;
      }
    }
  }
  cout << ans << endl;
  return 0;
}
