leecode 解题总结:79. Word Search

#include <iostream>
#include <stdio.h>
#include <vector>
#include <string>
using namespace std;
/*
问题:
Given a 2D board and a word, find if the word exists in the grid.

The word can be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once.

For example,
Given board =

[
  ['A','B','C','E'],
  ['S','F','C','S'],
  ['A','D','E','E']
]
word = "ABCCED", -> returns true,
word = "SEE", -> returns true,
word = "ABCB", -> returns false.

分析:这是明显的深度优先搜索问题。可以对当前位置(i,j)对应的字符,如果该字符等于给定字符串上对应位置的
字符,说明找到了当前位置。后续进行上下左右4个位置的继续查找,一旦发现位置上的字符不等于给定
单词对应位置字符,立即终止这个方向的搜索

这个不应该是递归,应该是回溯,一旦碰到当前字符不等后,需要回溯到上一个结果。
回溯的话只能判定当前,而不能像递归一样直接尝试下一个,回溯应该是先判定当前是否可能,如果不可能,再做

输入:
3(行数)  ABCCED(待查找字符串)
ABCE
SFCS
ADEE

3  SEE
ABCE
SFCS
ADEE

3  ABCB
ABCE
SFCS
ADEE

1 a
a
1 abc
ab
1 b
a
2 cdba
ab
cd

3  ABCESEEEFS
ABCE
SFES
ADEE
输出:
true
true 
false
false

关键:
1 典型的回溯问题,罗列所有起点+回溯
回溯:一开始就对当前遍历元素的正确和错误状态指出,访问标记一定要先设置,然后回溯结束,重置
回溯开始部分会检查位置是否超出,则递归时无需再检查,这样是重复处理,而且会导致错误
bool dfs(vector<vector<char>>& board, string word, int pos ,int curRow , int curCol , vector<vector<int>>& visited)
{
	//找到结果,返回true
	if(pos == word.length())
	{
		return true;
	}
	int colMax = board.at(0).size();//x最大值为列数
	int rowMax = board.size();//y最大值为行数
	if(curRow < 0 || curRow >= rowMax || curCol < 0 || curCol >= colMax)
	{
		return false;
	}
	if(board.at(curRow).at(curCol) != word.at(pos))
	{
		//需要回溯
		return false;
	}
	//说明当前是可以继续向下操作的,需要设置访问标记.但是如果是由字符不等,则不需要设置访问标记,因为后续还可能用到
	if(visited.at(curRow).at(curCol))
	{
		return false;
	}
	visited.at(curRow).at(curCol) = 1;//部分先成功后失败的字符访问标记可能会导致后续查找失败,这里需要重新设置
	bool isOk = 
		dfs(board , word , pos + 1 , curRow + 1 , curCol , visited) || 
		dfs(board , word , pos + 1 , curRow - 1 , curCol , visited) ||
		dfs(board , word , pos + 1 , curRow , curCol + 1 , visited) ||
		dfs(board , word , pos + 1 , curRow , curCol - 1 , visited);
	visited.at(curRow).at(curCol) = 0;//回溯需要
	return isOk;
}
*/

int g_next[][2] = {
	{-1 , 0},//上
	{1 , 0},//下
	{0, -1},//左
	{0,1}//右
}; 

class Solution {
public:
	//, vector< vector<int> >& visited
	bool dfs2(vector<vector<char>>& board, string word, int pos ,int curRow , int curCol , vector<vector<int>>& visited)
	{
		//找到结果,返回true
		if(pos == word.length())
		{
			return true;
		}
		int row;
		int col;
		int colMax = board.at(0).size();//x最大值为列数
		int rowMax = board.size();//y最大值为行数
		if(curRow < 0 || curRow >= rowMax || curCol < 0 || curCol >= colMax)
		{
			return false;
		}

		//是否访问过不能放在后续中,这是对当前元素判定的条件
		//如果以(x,y)处为起点的字符已经访问过,表示不可能,则直接跳过,因为一个元素只能用一次		
		if(visited.at(curRow).at(curCol))
		{
			return false;
		}
		//说明当前位置不行,为了复用位置,需要重新设定该位置为未访问
		visited.at(curRow).at(curCol) = 1;
		bool isFind = true;
		//需要先选定一个字符,进行比较
		//对四个方向遍历
		//如果当前位置字符与pos位置上字符相等,就尝试从4个方向对下一个字符处理,否则,应该重新设定新的起始位置(也是4个方向,这个需要标记数组)
		if(board.at(curRow).at(curCol) != word.at(pos))
		{
			//需要回溯
			return false;
		}
		//当前字符与字符串中对应字符,不等,需要重新选定起点
		else
		{
			for(int i = 0 ; i < 4 ; i++)
			{
				row = curRow + g_next[i][0];
				col = curCol + g_next[i][1];
				//范围校验不需要,//如果发现pos == word.length() - 1,也算正确,避免只有一行一列导致不能继续遍历情况,会导致有的情况不能处理
				//尝试继续访问
				bool isOk = dfs(board , word , pos + 1 , row , col ,visited);
				//如果从当前位置继续向下不可能,就应该换一个方向处理
				if(isOk)
				{
					return true;
				}
			}
		}
		//说明当前位置不行,为了复用位置,需要重新设定该位置为未访问
		visited.at(curRow).at(curCol) = 0;
		//防止一行一列因为不能上下左右搜索而被误认为是找不到
		return false;
	}

	bool dfs(vector<vector<char>>& board, string word, int pos ,int curRow , int curCol , vector<vector<int>>& visited)
	{
		//找到结果,返回true
		if(pos == word.length())
		{
			return true;
		}
		int colMax = board.at(0).size();//x最大值为列数
		int rowMax = board.size();//y最大值为行数
		if(curRow < 0 || curRow >= rowMax || curCol < 0 || curCol >= colMax)
		{
			return false;
		}
		if(board.at(curRow).at(curCol) != word.at(pos))
		{
			//需要回溯
			return false;
		}
		//说明当前是可以继续向下操作的,需要设置访问标记.但是如果是由字符不等,则不需要设置访问标记,因为后续还可能用到
		if(visited.at(curRow).at(curCol))
		{
			return false;
		}
		visited.at(curRow).at(curCol) = 1;//部分先成功后失败的字符访问标记可能会导致后续查找失败,这里需要重新设置
		bool isOk = 
			dfs(board , word , pos + 1 , curRow + 1 , curCol , visited) || 
			dfs(board , word , pos + 1 , curRow - 1 , curCol , visited) ||
			dfs(board , word , pos + 1 , curRow , curCol + 1 , visited) ||
			dfs(board , word , pos + 1 , curRow , curCol - 1 , visited);
		visited.at(curRow).at(curCol) = 0;//回溯需要
		return isOk;
	}

    bool exist(vector<vector<char>>& board, string word) {
		if(board.empty() || word.empty())
		{
			return false;
		}
		int row = board.size();
		int col = board.at(0).size();
		//罗列所有可能的起始位置
		bool isOk;
		//设定访问标记
		vector< vector<int> > visited( row , vector<int>(col , 0) );
		vector< vector<int> > visitedTemp;
		int pos;
		for(int i = 0; i < row ; i++)
		{
			for(int j = 0 ; j < col; j++)
			{
				//每次重新除法,都需要重新设定访问标记
				visitedTemp = visited;
				pos = 0;
				isOk = dfs(board , word , pos , i , j , visitedTemp);
				if(isOk)
				{
					return true;
				}
			}
		}
		return false;
    }
};

void process()
{
	 //vector<string> nums;
	 string value;
	 int num;
	 Solution solution;
	 vector<int> result;
	 vector< vector<char> > chars;
	 int len = 0;
	 string word;
	 while(cin >> num >> word )
	 {
		 chars.clear();
		 for(int i = 0 ; i < num ; i++)
		 {
			 cin >> value;
			 len = value.length();
			 vector<char> values;
			 for(int j = 0 ; j < len ; j++)
			 {
				 values.push_back(value.at(j));
			 }
			 chars.push_back(values);
		 }
		 bool isOk = solution.exist(chars , word);
		 if(isOk)
		 {
			 cout << "true" << endl;
		 }
		 else
		 {
			 cout << "false" << endl;
		 }
	 }
}

int main(int argc , char* argv[])
{
	process();
	getchar();
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值