剑指offer-面试题-回溯法之矩阵中的路径

1.回溯的基本原理

在问题的解空间中,按深度优先遍历策略,从根节点出发搜索解空间树。算法搜索至解空间的任意一个节点时,先判断该节点是否包含问题的解。如果确定不包含,跳过对以该节点为根的子树的搜索,逐层向其祖先节点回溯,否则进入该子树,继续深度优先搜索。

回溯法解问题的所有解时,必须回溯到根节点,且根节点的所有子树都被搜索后才结束。回溯法解问题的一个解时,只要搜索到问题的一个解就可结束。

2.回溯的基本步骤

2.1 定义问题的解空间

2.2 确定易于搜索的解空间结构

2.3 以深度优先搜索的策略搜索解空间,并在搜索过程中尽可能避免无效搜索

3.名企面试题:

请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。例如在下面的 3×4 的矩阵中包含一条字符串“bfce”的路径(路径中的字母用下划线标出)。但矩阵中不包含字符串“abfb”的路径,因为字符串的第一个字符 b 占据了矩阵中的第一行第二个格子之后,路径不能再次进入这个格子。

A	B	T	G
C	F	C	S
J	D	E	H

4.解题思路:

首先,在矩阵中任选一个格子作为路径的起点。如果路径上的第 i 个字符不是待搜索的目标字符ch,那么这个格子不可能处在路径上的第 i 个位置。如果路径上的第 i 个字符正好是 ch,那么往相邻的格子寻找路径上的第 i+1 个字符。除在矩阵边界上的格子之外,其他格子都有 4 个相邻的格子。重复这个过程直到路径上的所有字符都在矩阵中找到相应的位置。

下一个字符, 如果 4 个相邻的格子都没有匹配字符串中下一个的字符,表明当前路径字符串中字符在矩阵中的定位不正确,我们需要回到前一个,然后重新定位。

#include <stdio.h>
#include <string.h>

//matrix 美[ 'meɪtrɪks ] 矩阵, 母体,发源地
//8-27完成

bool hasPathCore(const char* matrix, int rows, int cols, int row, int col, const char* str, bool* visited, int& pathLenth)
{
	if (!matrix || rows < 0 || cols < 0 || !str)
	{
		return false;
	}
	if (str[pathLenth] == '\0') //当查找到字符串结束符时,说明找到,结束
	{
		return true;
	}
	bool haspath = false;
	if (col < cols && row < rows && matrix[row * cols + col] == str[pathLenth] && !visited[row * cols + col])
	{
		pathLenth++;
		visited[row * cols + col] = true;
		
		/*
		//对当前位置的前后左右进行查找对应的字符,直到找到对应的字符,或者所有位置查找完毕
			      ↑
			← 当前位置 →
			      ↓
		*/
		haspath = hasPathCore(matrix, rows, cols, row, col - 1, str, visited, pathLenth)
				|| hasPathCore(matrix, rows, cols, row - 1, col, str, visited, pathLenth)
				|| hasPathCore(matrix, rows, cols, row, col + 1, str, visited, pathLenth)
				|| hasPathCore(matrix, rows, cols, row + 1, col, str, visited, pathLenth);
		
		if (!haspath)
		{
			pathLenth--;
			visited[row * cols + col] = false;
		}
		
	}
	return haspath;
}

/*
const char* matrix:字符串
		 int rows:字符串分割的行数
		 int cols:字符串分割的行数
  const char* str:要查找的字符串

  如字符串:ABTGCFCSJDEH
  分手的字符阵为:
		ABTG
		CFCS
		JDEH
*/

bool hasPath(const char* matrix, int rows, int cols, const char* str)
{
	if (!matrix || rows < 0 || cols < 0 || !str)
	{
		return false;
	}

	bool* visited = new bool[rows * cols];
	memset(visited, 0, rows * cols); //全部置为0, 即false

	int pathLenth = 0;//从第一个字符开始查找

	for (int row = 0; row < rows; row++)//每一行的去查找
	{
		for (int col = 0; col < cols; col++)//每一列的去查找
		{
			if (hasPathCore(matrix, rows, cols, row, col, str, visited, pathLenth))
			{
				//找到字符串,释放内存
				delete[]visited;
				return true;
			}
		}
	}
	//字符阵的每一行每一列全部找完,无法找到对应的字符串,释放内存
	delete[]visited;
	return false;
}


int main(void)
{
	const char* matrix = "ABTGCFCSJDEH";//源字符串
	int row = 3;
	int col = 4;
	//根据源字符串分割为三行四列,只能90°查找,如ABFC, 不能ABCH这种
	/* ABTG
	*  CFCS
	*  JDEH
	*/
	//查找的字符串
	const char* str = "ABFCS";
	if (hasPath(matrix, row, col, str))
	{
		printf("此路径存在!\n");
	}
	else
	{
		printf("此路径不存在!\n");
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值