#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<string>
#include<stack>
#include<cstdio>
#include<cmath>
using namespace std;

typedef long long ll;
typedef long double ld;
typedef pair<int,int> P;
typedef pair<int,P> P1;

typedef unsigned char uc;

#define fr first
#define sc second
#define mp make_pair
#define pb push_back
#define rep(i,x) for(int i=0;i<x;i++)
#define rep1(i,x) for(int i=1;i<=x;i++)
#define rrep(i,x) for(int i=x-1;i>=0;i--)
#define rrep1(i,x) for(int i=x;i>0;i--)
#define sor(v) sort(v.begin(),v.end())
#define rev(s) reverse(s.begin(),s.end())
#define lb(vec,a) lower_bound(vec.begin(),vec.end(),a)
#define ub(vec,a) upper_bound(vec.begin(),vec.end(),a)
#define uniq(vec) vec.erase(unique(vec.begin(),vec.end()),vec.end())
#define mp1(a,b,c) P1(a,P(b,c))

const int INF=1000000000;
const int dir_4[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
const int dir_8[8][2]={{1,0},{1,1},{0,1},{-1,1},{-1,0},{-1,-1},{0,-1},{1,-1}};

//uc dp[400000010];

/*int ind(int i,int j,int k,int l){
	return ((372-i)*(i-1)/2+j-i)*93*185+((372-k)*(k-1)/2+l-k);
}*/

int main(){
	int h,w;
	char c[200][200];
	scanf("%d%d",&h,&w);
	rep1(i,h){
		scanf("\n");
		rep1(j,w)scanf("%c",&c[i][j]);
	}
	
	/*rep1(i,h)for(int j = i ; j <= h ; j ++){
		rep1(k,w)for(int l = k ; l <= w ; l ++){
			dp[ind(i,j,k,l)] = 0;
		}
	}*/
	
	static unsigned char dp1[200][200][200][20];
	static unsigned char dp2[200][200][200][20];
	int dp_memo[200][200];
	
	rrep1(x,h)rrep1(y,w){
		for(int i = x ; i <= h ; i ++){
			for(int j = y ; j <= w ; j ++){
				dp_memo[i][j] = 100;
			}
		}
		for(int i = x ; i <= h ; i ++){
			for(int j = y ; j <= w ; j ++){
				if((j == y || dp_memo[i][j-1] == 0) && (i == x || dp_memo[i-1][j] == 0) && c[x][y] == c[i][j]){
					dp_memo[i][j] = 0;
				}
			}
		}
		for(int i = x ; i <= h ; i ++){
			for(int j = y ; j <= w ; j ++){
				/*if((j == y || dp_memo[i][j-1] == 0) && (i == x || dp_memo[i-1][j] == 0) && c[x][y] == c[i][j]){
					dp_memo[i][j] = 0;
				}*/
				if(dp_memo[i][j] != 100){
					if(j == w || dp_memo[i][j+1] > dp_memo[i][j]){
						int s = dp_memo[i][j];
						int t = dp1[x][j+1][i][dp_memo[i][j]];
						while(t == 0 && s < 19){
							s ++;
							t = dp1[x][j+1][i][s];
						}
						if(t != 0){
							while(dp_memo[i][t] > s+1){
								dp_memo[i][t] = s+1;
								t --;
							}
						}
					}
					if(i == h || dp_memo[i+1][j] > dp_memo[i][j]){
						int s = dp_memo[i][j];
						int t = dp2[i+1][y][j][dp_memo[i][j]];
						while(t == 0 && s < 19){
							s ++;
							t = dp2[i+1][y][j][s];
						}
						if(t != 0){
							while(dp_memo[t][j] > s+1){
								dp_memo[t][j] = s+1;
								t --;
							}
						}
					}
				}
			}
		}
		for(int i = x ; i <= h ; i ++){
			rep(k,20)dp1[x][y][i][k] = 0;
		}
		for(int j = y ; j <= w ; j ++){
			rep(k,20)dp2[x][y][j][k] = 0;
		}
		for(int i = x ; i <= h ; i ++){
			for(int j = w ; j >= y ; j --){
				if(dp_memo[i][j] == 100)continue;
				if(dp1[x][y][i][dp_memo[i][j]] == 0)dp1[x][y][i][dp_memo[i][j]] = j;
			}
			rep(k,19)dp1[x][y][i][k+1] = max( dp1[x][y][i][k] , dp1[x][y][i][k+1] );
		}
		for(int j = y ; j <= w ; j ++){
			for(int i = h ; i >= x ; i --){
				if(dp_memo[i][j] == 100)continue;
				if(dp2[x][y][j][dp_memo[i][j]] == 0)dp2[x][y][j][dp_memo[i][j]] = i;
			}
			rep(k,19)dp2[x][y][j][k+1] = max( dp2[x][y][j][k] , dp2[x][y][j][k+1] );
		}
	}
	
	/*rep(k,19){
		cout << dp1[h][w][h][k] << endl;
	}*/
	
	rep(k,19){
		//cout << dp1[1][1][h][k] << endl;
		if(dp1[1][1][h][k] == w){
			cout << k << endl;
			return 0;
		}
	}
}


Measured memory_bytes: 292480