剑指Offer刷题记录_Day14

搜索与回溯(中等)

Q1 矩阵中的路径

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

  1. 解题思路:DFS + 剪枝

    • DFS:通过递归,先朝一个方向搜到底,再回溯至上个节点,沿另一个方向搜索,以此类推。
    • 剪枝: 遇到能提前判断不可能匹配成功时,将停止搜索该分支
  2. DFS具体思路:

    • 参数:行索引 i ,列索引 j ,当前将匹配的字符在字符串中的位置k
    • 标记当前矩阵元素,将board[ i ] [ j ] 修改为空字符表示已经走过该位置,若该位置的所以方向都探寻失败,需恢复该位置的字符;
    • 搜索下一步,按照上下左右顺序,每一分支DFS,搜索成功则停止,不再继续搜素。
    • 返回值:bool类型
  3. 剪枝判断条件:

    • 当前元素与目标字符不匹配
    • 元素已经被访问
class Solution {
public:
    bool exist(vector<vector<char>>& board, string word) {

        rows = board.size();
        cols = board[0].size();
        for(int i=0;i<rows;i++)
          for(int j=0;j<cols;j++)
            if(DFS(board,word,i,j,0)) return true;
        return false;
    }
private:
    int rows,cols;
    bool DFS(vector<vector<char>>& board,string word,int i,int j,int k)
    {
        //终止条件1
        if(i>=rows || j>=cols || i<0 || j<0) return false;
        //终止条件2
        if(word[k] != board[i][j]) return false;
        //终止条件3
        if(k == word.size()-1)  return true;
        board[i][j] = '\0'; //标记
        bool r = DFS(board,word,i+1,j,k+1)||DFS(board,word,i-1,j,k+1)||DFS(board,word,i,j-1,k+1)||DFS(board,word,i,j+1,k+1);
        board[i][j] = word[k];
        return r;    
     }
   
};

Q2 机器人的运动范围

地上有一个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。请问该机器人能够到达多少个格子?

本题与第一题类似,区别在于需要记录符合“小于K”的能到达的方格数,我们可以参照上题修改变量和条件。

class Solution {
public:
    int movingCount(int m, int n, int k) {

       vector<vector<int>> board(m,vector<int>(n,0)); 
       rows = m;
       cols = n;
       return DFS(board,0,0,k);

    }
    private:
    int rows,cols,count_n = 0;
    int DFS(vector<vector<int>>& board,int i,int j,int k)
    {
        //剪枝1
        if(i>=rows || j>=cols || i<0 || j<0) return 0;
        //剪枝2
        int sum = 0,a=i,b=j;
        while(a)
        {
            sum += a%10;
            a = a/10 ; 
        }
        while(b)
        {
            sum += b%10;
            b = b/10;
        }
        if(sum > k) return 0;
        //剪枝3
        if(board[i][j]==-2) return 0;

        board[i][j] = -2;         //标记
        count_n ++;
        DFS(board,i+1,j,k);
        DFS(board,i-1,j,k);
        DFS(board,i,j-1,k);
        DFS(board,i,j+1,k);  

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值