#pragma comment(linker, "/STACK:512000000")
#define _CRT_SECURE_NO_WARNINGS
//#include "testlib.h"
#include <bits/stdc++.h>
#ifdef AIM
#include <sys/resource.h>
#endif
using namespace std;

#define all(a) a.begin(), a.end()
using li = long long;
using ld = long double;
void solve(bool);
void precalc();
clock_t start;
int main() {
#ifdef AIM
  freopen("/home/alexandero/CLionProjects/ACM/input.txt", "r", stdin);
  //freopen("/home/alexandero/CLionProjects/ACM/output.txt", "w", stdout);
//freopen("out.txt", "w", stdout);
#else
  //freopen("input.txt", "r", stdin);
//freopen("output.txt", "w", stdout);
#endif

#ifdef AIM
  const rlim_t kStackSize = 256 * 1024 * 1024;
  struct rlimit rl;
  int result;

  result = getrlimit(RLIMIT_STACK, &rl);
  if (result == 0) {
    if (rl.rlim_cur < kStackSize) {
      rl.rlim_cur = kStackSize;
      result = setrlimit(RLIMIT_STACK, &rl);
      if (result != 0) {
        fprintf(stderr, "setrlimit returned result = %d\n", result);
      }
    }
  }
#endif

  start = clock();
  int t = 1;
#ifndef AIM
  cout.sync_with_stdio(0);
  cin.tie(0);
#endif
  cout.precision(20);
  cout << fixed;
  //cin >> t;
  precalc();
  while (t--) {
    solve(true);
  }
  cout.flush();

#ifdef AIM1
  while (true) {
    solve(false);
  }
#endif

#ifdef AIM
  cerr << "\n\n time: " << (clock() - start) / 1.0 / CLOCKS_PER_SEC << "\n\n";
#endif
  return 0;
}

//BE CAREFUL: IS INT REALLY INT?

template<typename T>
T binpow(T q, T w, T mod) {
  if (!w)
    return 1 % mod;
  if (w & 1)
    return q * 1LL * binpow(q, w - 1, mod) % mod;
  return binpow(q * 1LL * q % mod, w / 2, mod);
}

template<typename T>
T gcd(T q, T w) {
  while (w) {
    q %= w;
    swap(q, w);
  }
  return q;
}
template<typename T>
T lcm(T q, T w) {
  return q / gcd(q, w) * w;
}

template <typename T>
void make_unique(vector<T>& vec) {
  sort(all(vec));
  vec.erase(unique(all(vec)), vec.end());
}

template<typename T>
void relax_min(T& cur, T val) {
  cur = min(cur, val);
}

template<typename T>
void relax_max(T& cur, T val) {
  cur = max(cur, val);
}

mt19937 rng((unsigned long long)chrono::steady_clock::now().time_since_epoch().count());

void precalc() {

}

//#define int li
//const li mod = 1000000007;
//const int mod = 998244353;
//using ull = unsigned long long;

const int C = 190;
int dp_vert[2][C][C][C];
int dp_hor[2][C][C][C];

void solve(__attribute__((unused)) bool read) {
  int n, m;
  //read = false;
  if (read) {
    cin >> n >> m;
  } else {
    n = 185;
    m = 185;
  }
  vector<string> matrix(n);
  for (int i = 0; i < n; ++i) {
    if (read) {
      cin >> matrix[i];
    } else {
      for (int j = 0; j < m; ++j) {
        matrix[i] += "#."[rand() & 1];
      }
    }
  }
  int par = 0;
  for (int u = n; u >= 0; --u) {
    for (int l = 0; l < m; ++l) {
      bool has_white = false, has_black = false;
      for (int r = l + 1; r <= m; ++r) {
        if (u == n) {
          dp_vert[par][u][l][r] = u;
          continue;
        }
        has_white |= (matrix[u][r - 1] == '#');
        has_black |= (matrix[u][r - 1] == '.');
        dp_vert[par][u][l][r] = u;
        if (!has_black || !has_white) {
          dp_vert[par][u][l][r] = u + 1;
          if (u + 1 < n && matrix[u][l] == matrix[u + 1][l]) {
            dp_vert[par][u][l][r] = dp_vert[par][u + 1][l][r];
          }
        }
      }
    }
  }
  for (int u = m; u >= 0; --u) {
    for (int l = 0; l < n; ++l) {
      bool has_white = false, has_black = false;
      for (int r = l + 1; r <= n; ++r) {
        if (u == m) {
          dp_hor[par][u][l][r] = u;
          continue;
        }
        has_white |= (matrix[r - 1][u] == '#');
        has_black |= (matrix[r - 1][u] == '.');
        dp_hor[par][u][l][r] = u;
        if (!has_black || !has_white) {
          dp_hor[par][u][l][r] = u + 1;
          if (u + 1 < m && matrix[l][u] == matrix[l][u + 1]) {
            dp_hor[par][u][l][r] = dp_hor[par][u + 1][l][r];
          }
        }
      }
    }
  }
  int max_res = 0;
  for (int val = 0; ; ++val) {
    for (int u = 0; u <= n; ++u) {
      for (int l = 0; l < m; ++l) {
        for (int r = l + 1; r <= m; ++r) {
          dp_vert[par ^ 1][u][l][r] = dp_vert[par][u][l][r];
        }
      }
    }
    for (int u = 0; u <= m; ++u) {
      for (int l = 0; l < n; ++l) {
        for (int r = l + 1; r <= n; ++r) {
          dp_hor[par ^ 1][u][l][r] = dp_hor[par][u][l][r];
        }
      }
    }

    auto relax_rectangle = [&] (int lx, int rx, int ly, int ry) {
      relax_max(max_res, val + 1);
      relax_max(dp_vert[par ^ 1][lx][ly][ry], rx);
      relax_max(dp_hor[par ^ 1][ly][lx][rx], ry);
    };

    for (int u = 0; u <= n; ++u) {
      for (int l = 0; l < m; ++l) {
        for (int r = l + 1; r <= m; ++r) {
          int coord = dp_vert[par][u][l][r];
          int new_coord = dp_vert[par][coord][l][r];
          for (int i = coord + 1; i <= new_coord; ++i) {
            relax_rectangle(u, i, l, r);
          }
        }
      }
    }
    for (int u = 0; u <= m; ++u) {
      for (int l = 0; l < n; ++l) {
        for (int r = l + 1; r <= n; ++r) {
          int coord = dp_hor[par][u][l][r];
          int new_coord = dp_hor[par][coord][l][r];
          for (int i = coord + 1; i <= new_coord; ++i) {
            relax_rectangle(l, r, u, i);
          }
        }
      }
    }

    par ^= 1;
    if (max_res == val) {
      break;
    }
  }

  cout << max_res << endl;

}

Measured memory_bytes: 106880