/**我是挺想不开的用栈非递归做这道题, 希望大家不要向我学习
* 以下言论纯属自我体会,接受优化
* 用栈存储当前合法访问路径,与str对应,用pathIndex做索引。
* 我认为非递归做这道题最主要的坑是在访问标记这块,
* 当栈顶字符的上下左右有不少于1个可访问字符时,
* 控制字符的访问标记
*/
public static boolean hasPath(char[] matrix, int rows, int cols, char[] str)
{
//判断参数合法性
if(matrix==null|| matrix.length==0) return false;
if(matrix.length!=rows*cols) return false;
if(str==null||str.length==0) return true;
if(str.length>matrix.length) return false;
if(str.length==matrix.length){
for(int m = 0;m<str.length;m++){
if(matrix[m]!=str[m])
return false;
}
return true;
}
//用stack 保留当前的寻找路径,如果不合适就pop,
//继续搜寻top字符的上下左右未被访问的元素
int len = rows*cols;
int pathIndex=0; //始终指向下一个字符目标
int row=0; //row和col始终表示当前已确定字符路径的last字符在matrix中的位置。
int col=0;
Stack<Character> pathStack = new Stack<Character>();
char[] state = new char[len];//记录matrix里字符的访问标记
int[] position = new int[str.length];
for(int t=0;t<len;t++)
state[t] = ‘F’;
int i=0;
while(i<len){
if(matrix[i] == str[0])
{
//
System.out.println(“stack[0] = ” + matrix[i]);
pathStack.push(matrix[i]);
position[pathIndex] = i; //记录栈里字符的位置,以便日后弹出时有所记录
//
System.out.println(“position of stack[0] = ” + i);
pathIndex++;
state[i] = ‘T’;
row = i/cols;
col = i-row*cols;
break;
}
i++;
}
if(i>=len) return false;
int k=0;
while(!pathStack.empty()){
//
System.out.println(“pathStack.empty() = “+ pathStack.empty());
if(pathIndex==str.length) return true; //表示已经找到字符路径
int preRow = row;//记录当前栈顶的位置,当其上下左右无节点可访问时有所用
int preCol = col;
if(isSatisfied(matrix,cols,row-1,col,pathIndex,position, str, state)){
row = row-1;
pathStack.push(str[pathIndex]);
pathIndex++;
}else if(isSatisfied(matrix,cols,row+1,col,pathIndex, position, str, state)){
row=row+1;
pathStack.push(str[pathIndex]);
pathIndex++;
}
else if(isSatisfied(matrix,cols,row,col+1,pathIndex,position, str, state)){
col = col+1;
pathStack.push(str[pathIndex]);
pathIndex++;
}
else if(isSatisfied(matrix,cols,row,col-1,pathIndex,position, str, state)){
col = col-1;
pathStack.push(str[pathIndex]);
pathIndex++;
}
else{
//说明当前栈顶字符的上下左右字符都不合适,那只能弹出栈顶字符。
//
此时如果栈非空,那么row,col记录栈顶元素位置(从position[]中可以拿到);
//
如果栈空了,那么就从上一个站内元素的下一个位置开始找==str[pathIndex]的字符入栈。
pathIndex–;
pathStack.pop();
if(pathIndex==0){
for(k=preRow*cols+preCol+1;k<len;k++){
if(matrix[k]==str[pathIndex]&&state[k]==’F’){
pathStack.push(matrix[k]);
position[pathIndex] = k;
pathIndex++;
state[k] = ‘T’;
row = k/cols;
col = k-row*cols;
break;
}
}
}else{
row = position[pathIndex-1]/cols;
col = position[pathIndex-1]-row*cols;
}
//!!!!很重要的地方,
//
如果栈顶字符Top的上下左右有两个及以上多个字符都是可访问的,
//
那么当确定了其中一个字符(ch1)走不通的时候弹出ch1,
//
如果在弹出栈后直接置ch1的state为‘F’,
//
那么会再次判断Top的上下左右是否可访问,
//
ch1又会被判断为可访问,如此便会陷入死循环。
//
因此这个语句就是为了避免如此死循环的
if(!(preRow==row-1||preRow==row+1||preCol==col-1||preCol==col+1)){
state[preRow*cols+preCol] = ‘F’;
}
}
}
return false;
}
public static boolean isSatisfied(char[] matrix,int cols,int row, int col,int pathIndex,int[] position,char[] str,char[] state){
//主要用来判断元素是否满足条件(未被访问过,并且是等于下一个需要的字符)
if(row<0||row>=(matrix.length/cols)||col<0||col>=cols) return false;
int index = row*cols+col;
if(state[index]==’F’&& matrix[index]==str[pathIndex]){
position[pathIndex]=index; //记录已访问路径元素的位置
state[index]=’T’;
pathIndex++;
return true;
}
return false;
}