#include <bits/stdc++.h>
using namespace std;

typedef vector<int> VI;
typedef vector<VI> VVI;
typedef vector<string> VS;
typedef pair<int, int> PII;
typedef long long LL;
typedef pair<LL, LL> PLL;

#define ALL(a)  (a).begin(),(a).end()
#define RALL(a) (a).rbegin(), (a).rend()
#define PB push_back
#define EB emplace_back
#define MP make_pair
#define SZ(a) int((a).size())
#define EACH(i,c) for(typeof((c).begin()) i=(c).begin(); i!=(c).end(); ++i)
#define EXIST(s,e) ((s).find(e)!=(s).end())
#define SORT(c) sort((c).begin(),(c).end())

#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define REP(i,n)  FOR(i,0,n)

#define FF first
#define SS second
template<class S, class T>
istream& operator>>(istream& is, pair<S,T>& p){
  return is >> p.FF >> p.SS;
}

const double EPS = 1e-10;
const double PI  = acos(-1.0);
const LL MOD = 1e9+7;
const int INF = 1e9;

int H, W;
map<PII,int> memo;
// sit -> tid　へ行く時の最大値
int dfs(int sid, int tid, VVI& reachable, VVI& lowids, VVI& upids){
  if(memo.count(MP(sid,tid))) return memo[MP(sid,tid)];
  int& res = memo[MP(sid,tid)];
  REP(c,26){
	for(auto l: lowids[c])
	  for(auto u: upids[c]){
		if(l!=sid && u!=tid && reachable[sid][l] == 0 && reachable[u][tid] == 0 && reachable[l][u] == 0)
		  res =max(res, 1+dfs(sid, l, reachable, lowids, upids)
				   + dfs(l, u, reachable, lowids, upids)
				   + dfs(u, tid, reachable, lowids, upids));
	  }
  }
  return res;
}

int main(){
  cin.tie(0);
  ios_base::sync_with_stdio(false);

  while(cin>>H>>W,H>0){memo.clear();
	VS vs(H);
	REP(i,H) cin >> vs[i];
	//if(vs[0][0] == '.') vs[0][0] = 'z'+1;
	//if(vs.back().back() == '.') vs.back().back() = 'z'+2;

	map<PII,int> ids; // 座標と対応するid
	map<int,char> ch; // idに対応するその文字
	int num = 0;
	for(int y=0;y<H;++y)
	  REP(x,W)
		if(vs[y][x] != '.' && vs[y][x] != '#'){
		  ch[num] = vs[y][x];
		  ids[MP(x,y)] = num++;
		}

	VVI dist(num+2, VI(num+2, -1)); // ふたつのid: i,jについて dist[i][j] = 0 iff i -> j が存在
	REP(y,H) REP(x,W)
	  if(ids.count(MP(x,y))){
		int id = ids[MP(x,y)];
		queue<PII> q;
		map<PII,bool> vis;
		q.push(PII(x,y));
		vis[PII(x,y)] = true;
		while(!q.empty()){
		  PII p = q.front(); q.pop();
		  if(ids.count(p)){
			dist[id][ids[p]] = 0;
		  }

		  for(auto dp: {PII(0,1), PII(1,0)}){
			p.FF += dp.FF;
			p.SS += dp.SS;
			if(p.FF < W && p.SS < H && vs[p.SS][p.FF] != '#' && !vis[p]){
			  q.push(p);
			  vis[p] =true;
			}
			p.FF -= dp.FF;
			p.SS -= dp.SS;
		  }
		}
	  }

	int S = num, T = num+1;
	{
	  queue<PII> q;
	  map<PII,bool> vis;
	  q.push(PII(0,0));
	  vis[PII(0,0)] = true;
	  while(!q.empty()){
		PII p = q.front(); q.pop();
		if(ids.count(p)){
		  dist[S][ids[p]] = 0;
		}
		
		for(auto dp: {PII(0,1), PII(1,0)}){
		  p.FF += dp.FF;
		  p.SS += dp.SS;
		  if(p.FF < W && p.SS < H && vs[p.SS][p.FF] != '#' && !vis[p]){
			q.push(p);
			vis[p] =true;
		  }
		  p.FF -= dp.FF;
		  p.SS -= dp.SS;
		}
	  }
	}
	{
	  queue<PII> q;
	  map<PII,bool> vis;
	  q.push(PII(W-1,H-1));
	  vis[PII(W-1,H-1)] = true;
	  while(!q.empty()){
		PII p = q.front(); q.pop();
		if(ids.count(p)){
		  dist[ids[p]][T] = 0;
		}
		if(p == MP(0,0))
		  dist[S][T] = 0;
		
		for(auto dp: {PII(0,-1), PII(-1,0)}){
		  p.FF += dp.FF;
		  p.SS += dp.SS;
		  if(p.FF >= 0 && p.SS >= 0 && vs[p.SS][p.FF] != '#' && !vis[p]){
			q.push(p);
			vis[p] =true;
		  }
		  p.FF -= dp.FF;
		  p.SS -= dp.SS;
		}
	  }
	}
	if(dist[S][T] != 0){
	  cout << -1 << endl;
	  continue;
	}

	VVI lower(26), upper(26);
	for(auto& id: ids)
	  if('a' <= ch[id.SS] && ch[id.SS] <= 'z')
		lower[ch[id.SS]-'a'].PB(id.SS);
	  else if('A' <= ch[id.SS] && ch[id.SS] <= 'Z')
		upper[ch[id.SS]-'A'].PB(id.SS);

	int ans = dfs(S, T, dist, lower, upper);
  	cout << ans << endl;
  }
  
  return 0;
}

Measured memory_bytes: 5084