剑指offer--矩阵中的路径(回溯解法典型题)+ 同类型题 :机器人的运动范围

说点题外的废话:如果有一些跟我一样的朋友在看这种就是感觉很难的题有点头大的时候,一定一定要静下心来,我们可以好几天就看这一道题,慢慢理解就好了。
题目:
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。例如,在下面的3×4的矩阵中包含一条字符串“bfce”的路径但矩阵中不包含字符串“abfb”的路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入这个格子。
在这里插入图片描述

分析:
给定一个字符串 在一个矩阵中寻找是否存在这个字符串 我们应该首先找到这个字符串开头的第一个字符 才能有下文,我们循环遍历这个数组,如果找到开头的第一个字符1,接下来就是要看这个字符1是否存在有相邻位置(行不变,列加减1,列不变,行加减1)的字符2等于字符串第二个字符的,对于相邻位置有存在的,则再看这个字符2是否存在有相邻位置的字符3等于字符串第三个字符的 … … ,直到走过的路径长度等于字符串长度,则这个矩阵里面存在包含字符串所有字符的路径。

假如我们字符串的前两个字符都找到了,现在在寻找字符串的第三个字符,但是第二个字符的上下左右相邻的位置都不是第三个字符,那么证明这条路径行不通,第二个字符的位置是不对的,我们要返回到第一个字符,重新定位第二个字符的位置。
由于路径不能重复进入矩阵的格子,所以还需要定义一个与字符矩阵大小相同的布尔值矩阵,用来标识路径是否已经进入过该节点。

 bool exist(vector<vector<char>>& board, string word) {
    
    
        
        int a = board.size();
        int b = board[0].size();
        if(a < 1||b < 1) return false;
        int pathLength = 0;
        vector<vector<bool>> visited(a,vector<bool>(b,false)); 
        for(int i = 0;i < a;i++){
    
    
            for(int j = 0;j < b;j++){
    
    
                if(existCore(board,pathLength,i,j,word,visited))
                return true;
            }
        }
        return false;
    }

    bool existCore(vector<vector<char>>& board,int pathLength, int cow,int col,string word, vector<vector<bool>> &visited){
    
    
        int b = board[0].size();
        int a = board.size();

        if(pathLength == word.length()) return true;
        bool hasPath = false;

        if(cow >= 0 && col >= 0 && cow < a && col<b && board[cow][col] == word[pathLength] && visited[cow][col] == false){
    
    
            pathLength++;
            visited[cow][col] = true;

            hasPath = existCore(board,pathLength,cow+1,col,word,visited)||
                      existCore(board,pathLength,cow,col-1,word,visited)||
                      existCore(board,pathLength,cow,col+1,word,visited)||
                      existCore(board,pathLength,cow-1,col,word,visited);
            if(!hasPath){
    
    
                pathLength--;
                visited[cow][col] = false;
            }
        }
        return hasPath;
    }

题目:
地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?

分析:
这个题猛的一看可能觉得比上面那个题难,但是这两个题其实就差在能否进入到相邻格子的条件里,其余的思路大概都是一样的,机器人从(0,0)开始移动,如果他能进入到(i,j)的格子里,在判断它能否进入到这个格子相邻的四个格子里,因为每一个格子相邻的格子之间存在重叠,所以我们仍然需要一个布尔值的数组来记录我们是否进入过这个格子,如果进入过那么这次就不会进入,也就不会使计数发生重复。

#include<iostream>
#include<vector>

using namespace std;
int movingCountCore(int k,int m,int n,int cow,int col,vector<vector<bool>>&visited);
bool check(int k,int m,int n,int cow,int col,vector<vector<bool>>&visited);
int getnums(int number);
int movingCount(int m, int n, int k){
    
    
	if(m <= 0 || n <= 0||k < 0) return 0;
	vector<vector<bool>> visited(m,vector<bool>(n,false));
	int count = movingCountCore(k,m,n,0,0,visited);
	return count;
}
int movingCountCore(int k,int m,int n,int cow,int col,vector<vector<bool>>&visited){
    
    
	int count = 0;
	if(check(k,m,n,cow,col,visited)){
    
    
		visited[cow][col] = true;
                //能进入到这个格子里count自然就需要加1
		count = 1 + movingCountCore(k,m,n,cow,col+1,visited)+
			        movingCountCore(k,m,n,cow,col-1,visited)+
				    movingCountCore(k,m,n,cow+1,col,visited)+
				    movingCountCore(k,m,n,cow-1,col,visited);
	}
	return count;
}

bool check(int k,int m,int n,int cow,int col,vector<vector<bool>>&visited){
    
    
	if(cow >= 0 && col >= 0 && cow<m && col<n && visited[cow][col] == false && getnums(cow) + getnums(col) <= k)
		return true;
	return false;
}
int getnums(int number){
    
    
	int result = 0;
	while(number != 0){
    
    
		result = result +number%10;
		number = number / 10;
	}
	return result;
}
int main()
{
    
    
	int m = 2;
	int n = 3;
	int k = 1;
	cout<<movingCount( m, n, k)<<endl;

	return 0;
}
 

与其感慨路难行,不如马上出发。

猜你喜欢

转载自blog.csdn.net/scarificed/article/details/120281548