#include<iostream>
#include<vector>
#include<deque>
using namespace std;

template<typename T>class Graph{
    public:
    struct edge{int to;T cost;};
    int Vertex_num,Edge_num;
    vector<edge>*g;

    const T INF=1000000000;

    Graph(int V){//0～V-1
        Vertex_num=V;
        g=new vector<edge>[V];
    }

    Graph(int V,int E){//0～V-1
        Vertex_num=V;
        Edge_num=E;
        g=new vector<edge>[V];
    }

    void emplace_back(int from,int to,T cost){
        edge e={to,cost};
        g[from].push_back(e);
        //edges->push_back(e);//for Bellman-Ford
    }

    void input(bool direct,bool weight){
        int from,to;
        T cost;
        for(int i=0;i<Edge_num;i++){
            cin>>from>>to;
            from--,to--;
            if(weight)cin>>cost;
            else cost=1;
            this->emplace_back(from,to,cost);
            if(!direct)this->emplace_back(to,from,cost);
        }
    }

    void check(){
        for(int i=0;i<Vertex_num;i++){
            cout<<"Vertex "<<i<<endl;
            for(auto x:g[i])cout<<x.to<<" "<<x.cost<<endl;
        }
    }
};

template<typename T>vector<T>bfs(Graph<T>graph,int start){
    vector<T>dist(graph.Vertex_num,-1);//訪問:startからの距離 未訪問:-1
    deque<int>q;
    q.push_front(start);
    dist[start]=0;
    while(!q.empty()){
        int p=q.front();q.pop_front();
        for(auto x:graph.g[p])if(dist[x.to]==-1){
            dist[x.to]=dist[p]+x.cost;
            if(x.cost)q.push_back(x.to);
            else q.push_front(x.to);
        }
        //visited[]の更新はpushするときにやらないとqueueがあふれる↑
    }
    return dist;
}

int H,W,S,G;
int main(){
    cin>>H>>W;
    char a[H][W];
    for(int i=0;i<H*W;i++)cin>>a[i/W][i%W];

    int d4[5]={1,0,-1,0,1};
    Graph<int>g(H*W+26);
    for(int i=0;i<H;i++){
        for(int j=0;j<W;j++){
            if(a[i][j]=='#')continue;
            if(a[i][j]=='S')S=i*W+j;
            if(a[i][j]=='G')G=i*W+j;
            if('a'<=a[i][j]&&a[i][j]<='z'){
                g.emplace_back(i*W+j,H*W+a[i][j]-'a',1);
                g.emplace_back(H*W+a[i][j]-'a',i*W+j,0);
                g.Edge_num+=2;
            }
            for(int k=0;k<4;k++){
                int x=i+d4[k],y=j+d4[k+1];
                if (x<0||x>=H||y<0||y>=W||a[x][y]=='#')continue;
                g.emplace_back(i*W+j,x*W+y,1);
                g.Edge_num++;
            }
        }
    }
    auto d=bfs(g,S);
    cout<<d[G]<<endl;
    return 0;
}
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <queue>
#include <vector>
using namespace std;
typedef pair<int,int> pii;
int h,w,dis[4000500],sx,sy,tx,ty,vis[4000500];
char sp[2005][2005];
priority_queue<pii > q;
vector<int> gg[30];

int dx[4]={0,-1,0,1};
int dy[4]={1,0,-1,0};

int dp(int i,int j){return i*w+j;}

int main()
{
	scanf("%d%d",&h,&w);
	for(int i=0;i<h;i++)
		scanf("%s",sp[i]);
	for(int i=0;i<h;i++)
		for(int j=0;j<w;j++)
		{
			if(sp[i][j]=='S') sx=i,sy=j;
			if(sp[i][j]=='G') tx=i,ty=j;
			if(sp[i][j]>='a' && sp[i][j]<='z')
				gg[sp[i][j]-'a'].push_back(i*w+j);
		}
	memset(dis,-1,sizeof(dis));
	dis[sx*w+sy]=0;
	q.push(make_pair(0,sx*w+sy));
	while(!q.empty())
	{
		int now=q.top().second;q.pop();
		if(vis[now]) continue;vis[now]=1;
		if(now<h*w){
			int x=now/w,y=now%w;
			for(int a=0;a<4;a++)
			{
				int nx=x+dx[a],ny=y+dy[a];
				if(nx>=0 && nx<h && ny>=0 && ny<w && sp[nx][ny]!='#' && (dis[nx*w+ny]==-1 || dis[nx*w+ny]>dis[now]+1))
				{
					dis[nx*w+ny]=dis[now]+1;
					q.push(make_pair(-dis[nx*w+ny],nx*w+ny));
				}
			}
			if(sp[x][y]>='a' && sp[x][y]<='z')
			{
				int c=sp[x][y]-'a';
				if(dis[c+h*w]==-1 || dis[c+h*w]>dis[now])
				{
					dis[c+h*w]=dis[now];
					q.push(make_pair(-dis[c+h*w],c+h*w));
				}
			}
		} else {
			int c=now-h*w;
			for(int i=0;i<gg[c].size();i++)
			{
				if(dis[gg[c][i]]==-1 || dis[gg[c][i]]>dis[now]+1)
				{
					dis[gg[c][i]]=dis[now]+1;
					q.push(make_pair(-dis[gg[c][i]],gg[c][i]));
				}
			}
		}
	}
	// cout<<dis[dp(0,1)]<<" "<<dis[]
	printf("%d\n",dis[tx*w+ty]);
	return 0;
}