79.Word Search

题目描述

求解给定字符串str,是否在字符矩阵array中。要求str中相邻的两个字符,在array中也是相邻字符,并且要求,array中的同一字符,不能使用两次;

我的解法

  • Beat 66%
  • 回溯法+剪枝
    必然要对每一点的每一条路径进行深度遍历,遍历过程中一旦出现:
    1.数组越界、2.该点已访问过、3.该点的字符和word对应的index字符不匹配 就要对该路径进行剪枝
  • 用了多余空间isvisit[][]
    class Solution {
      public boolean dfs(int rowlen,int collen,String str,char [][] board,int [][] isvisit,int now,int i,int j){
      	boolean ok = false;
          if(now >= str.length()) return true;
          isvisit[i][j] = 1;
          if(j + 1 < collen && isvisit[i][j + 1] == 0 && str.charAt(now) == (board[i][j + 1])){
          	ok = dfs(rowlen,collen,str,board,isvisit,now + 1,i,j + 1) || ok;
          	if(ok) return ok;
          }
          if(j - 1 >= 0 && isvisit[i][j - 1] == 0 && str.charAt(now) == (board[i][j - 1]))  {
          	ok = dfs(rowlen,collen,str,board,isvisit,now + 1,i,j - 1) || ok;
          	if(ok) return ok;
          }
          if(i + 1 < rowlen && isvisit[i + 1][j] == 0 && str.charAt(now) == (board[i + 1][j]))  {
          	ok = dfs(rowlen,collen,str,board,isvisit,now + 1,i + 1,j) || ok;
          	if(ok) return ok;
          }
          if(i - 1 >= 0 && isvisit[i - 1][j] == 0 && str.charAt(now) == (board[i - 1][j]))  {
          	ok = dfs(rowlen,collen,str,board,isvisit,now + 1,i - 1,j) || ok;
          	if(ok) return ok;
          }
          isvisit[i][j] = 0;
          return ok;
      }
      public boolean exist(char[][] board, String word) {
      	int lenrow = board.length,lencol = board[0].length;
      	int [][] isvisit = new int[board.length][board[0].length];
      	for(int i = 0;i < lenrow;i++)
              for(int j = 0;j < lencol;j++)
              	isvisit[i][j] = 0;
          for(int i = 0;i < lenrow;i++)
              for(int j = 0;j < lencol;j++)
                  if(board[i][j] == word.charAt(0) && dfs(lenrow,lencol,word,board,isvisit,1,i,j))
                      return true;
          return false;
      }
    }
    

简便解法

  • 回溯法
  • 没用多余空间。
    由于英文字符范围是0~255,因此遍历某个字符后,进行c^=256操作,该字符在后续匹配中就不会再次匹配到,从而实现标记的效果。在回溯的时候需要将标记的字符还原。
public boolean exist(char[][] board, String word) {
    //巧妙,不用再挨个转换string了
    char[] w = word.toCharArray();
    for (int y=0; y<board.length; y++) {
    	for (int x=0; x<board[y].length; x++) {
    		if (exist(board, y, x, w, 0)) return true;
    	}
    }
    return false;
}

private boolean exist(char[][] board, int y, int x, char[] word, int i) {
	if (i == word.length) return true;
	if (y<0 || x<0 || y == board.length || x == board[y].length) return false;
	if (board[y][x] != word[i]) return false;
	//节约了空间!!!存储了遍历状态,若遍历了,做亦或操作后(用亦或的原因是再做一次亦或能回来),满足不等于word[i]
	board[y][x] ^= 256;
	//可以像我一样拆开,更节约时间
	boolean exist = exist(board, y, x+1, word, i+1)
		|| exist(board, y, x-1, word, i+1)
		|| exist(board, y+1, x, word, i+1)
		|| exist(board, y-1, x, word, i+1);
	//遍历之后要恢复到未访问的状态
	board[y][x] ^= 256;
	return exist;
}