剑指offer:矩阵中的路径问题,回溯法,非递归版本

/**我是挺想不开的用栈非递归做这道题, 希望大家不要向我学习

* 以下言论纯属自我体会,接受优化

* 用栈存储当前合法访问路径,与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;

}

 

    原文作者:回溯法
    原文地址: https://blog.csdn.net/siri96/article/details/80175854
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞