【剑指Offer】【回溯法】12_矩阵中的路径 + 13_机器人的运动范围(好难,还是不太会)⭐⭐⭐⭐

矩阵中的路径

题目:请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。 例如 a b c e s f c s a d e e 矩阵中包含一条字符串"bccced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。

 

A:回溯法是用递归实现的

  1、创建布尔型数组,用来标识路径查找(初始化为false,表示未走过/此路不通,true表示查找到了,不能走第二次)

  2、根据行数和列数,遍历矩阵,先找到匹配str字符串的第一个元素的矩阵元素

  3、str的已经判断到了最后一位,说明匹配成功

  4、确定递归终止条件:越界,当前找到的矩阵元素不等于目标数组对应位置的值,已经走过的===false,说明这条路不通

  5、递归不断地寻找周围四个格子( (row,col-1) , (row - 1,col) , (row,col+1) , (row+1,col) )是否符合条件,只要有一个格子符合条件,就继续递归查找,直到到达目标串末尾或者不满足递归条件就停止。

  6、还原一下布尔型数组的标志位,进入下一轮的判断。(回溯)

 

class Solution {
public:
    bool func_path(const char* matrix, int rows, int cols, const char* str, int row,int col, int &path, bool *flag)
    {
        if(str[path] == '\0')
        {
            return true;
        }
        bool hasPath = false;
        
        if( ((row >= 0) && (row <= rows)) && ((col >= 0) && (col <= cols)) //不越界
           && (matrix[row * cols + col] == str[path]) //找到字符,字符相等
           && (!flag[row * cols + col])) //路径不重复
        {
            path++;
            flag[row * cols + col] = true;
            
       //递归寻找周围四个格子 hasPath = func_path(matrix, rows, cols, str, row, col - 1, path, flag) ||func_path(matrix, rows, cols, str, row - 1, col, path, flag) ||func_path(matrix, rows, cols, str, row, col + 1, path, flag) ||func_path(matrix, rows, cols, str, row + 1, col, path, flag);
       //找不到,则回溯查找 if(hasPath == false) { --path; flag[row *cols + col] = false; } } return hasPath; } bool hasPath(char* matrix, int rows, int cols, char* str) { if((matrix == nullptr) || (rows < 1) || (cols < 1) || (str == nullptr)) { return false; } //bool类型数组,标识路径寻找 bool *flag = new bool[rows * cols]; memset(flag, 0, rows * cols);//初始化为false int path = 0; for(int i = 0; i < rows; i++) { for(int j = 0; j < cols; j++) { if(func_path(matrix, rows, cols, str, i, j, path, flag)) { return true; } } } delete[] flag; return false; } };

  

 

 

 

机器人的运动范围

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

 

A:机器人行走的格子可以看作是一个m*n的矩阵,在这个矩阵中,除边界的格子之外,其他格子都有4个相邻的格子。

  机器人从0,0开始移动,进入(i,j)格子前,检查坐标的数位和是否<=threshold,来判断机器人是否可以进入格子

  机器人如果可以进入格子,则判断它是否能够进入4个相邻格子

 

 

class Solution {
public:
    //计算坐标数位和
    int getSum(int number)
    {
        int sum = 0;
        while(number > 0)
        {
            sum += number % 10;
            number /= 10;
        }
        return sum;
    }
    //机器人能否走到(row,col)
    bool check(int threshold, int rows, int cols, int row, int col, bool *flag)
    {
        //是否越界
        if(((row >= 0) && (row < rows)) && ((col >= 0) && (col < cols))  
          && (getSum(row) + getSum(col) <= threshold) 
          && (!flag[row * cols + col]))
        {
            return true;
        }
        return false;
    }
    //计数:能走多少个方格
    int func_count(int threshold, int rows, int cols, int row, int col, bool *flag)
    {
        int count = 0;
        if(check(threshold, rows, cols, row, col, flag))
        {
            flag[row * cols + col] = true;
            
            count = 1 + func_count(threshold, rows, cols, row, col - 1, flag) 
                      + func_count(threshold, rows, cols, row - 1, col, flag)
                      + func_count(threshold, rows, cols, row, col + 1, flag)
                      + func_count(threshold, rows, cols, row + 1, col, flag);
        }
        return count;
    }
    int movingCount(int threshold, int rows, int cols)
    {
        if((threshold < 0) || (rows <= 0) || (cols <= 0))
        {
            return 0;
        }
        bool *flag = new bool[rows * cols];
        memset(flag, 0, rows * cols);
        
        int count = func_count(threshold, rows, cols, 0, 0, flag);
        
        delete[] flag;
        return count;
    }
};

  

 

 

相关题目:

  数组移动跳跃:给定一个非空的整数数组,从数组第一个元素(下标为0的元素)开始遍历进行移动,下一次向后或向前移动 该元素的值 的位数(值为正数向后移动,值为负数向前移动,值为零不移动),依次类推进行移动,若某次移动数组出现越界,则说明数组可以跳出,返回true;不能跳出则返回false;(加分项:也可考虑不增加使用其他集合数组辅助完成算法)

  有序矩阵中第k小的元素:给定一个 n x n 矩阵,其中每行和每列元素均按升序排序,找到矩阵中第k小的元素。请注意,它是排序后的第k小元素,而不是第k个元素。

   交换查询:小M有一个N*M的方格,行列下标均从0开始。其中有K个方格中有数字,表示为(X, Y)方格中有数字C。对方格有2种操作,交换方格的两行或者交换方格的两列。小M希望随时能够知道在经过一系列交换之后某一方格中是否含有数字,并且如果有的话,数字是多少。

  大家来扫雷:小M最近爱上了扫雷游戏,就是在一个n*m的区域中,有地雷,每一个方格上都有一个数字s,表示在这个方格周围有s颗雷,现在给你一张表明地雷的图,并且指定一个位置点开,请输出点开后的数字情况,若点开的地方的数字为0,则向该方格周围扩展,直到遇到数字或者地图边界为止,若点开的地方为地雷,那么直接输出"GG"。周围指的是上,左上,左,左下,下,右下,右,右上八个方向。

posted @ 2019-08-26 20:55  XieXinBei0318  阅读(233)  评论(0编辑  收藏  举报