乱序版 ● 剑指offer每日算法题打卡题解—— 搜索与回溯算法(题号12,13,34)

Posted 寂静花开

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了乱序版 ● 剑指offer每日算法题打卡题解—— 搜索与回溯算法(题号12,13,34)相关的知识,希望对你有一定的参考价值。

打卡day10

第一题:剑指 Offer 12. 矩阵中的路径

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

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

例如,在下面的 3×4 的矩阵中包含单词 “ABCCED”(单词中的字母已标出)。

示例 1:
输入:board = [[“A”,“B”,“C”,“E”],[“S”,“F”,“C”,“S”],[“A”,“D”,“E”,“E”]], word = “ABCCED”
输出:true

示例 2:
输入:board = [[“a”,“b”],[“c”,“d”]], word = “abcd”
输出:false

提示:
1 <= board.length <= 200
1 <= board[i].length <= 200
board 和 word 仅由大小写英文字母组成

来源:力扣(LeetCode)
链接:[https://leetcode-cn.com/problems/ju-zhen-zhong-de-lu-jing-lcof

](https://leetcode-cn.com/problems/ju-zhen-zhong-de-lu-jing-lcof)
解题思路:
矩阵搜索问题
以一个节点,向上下左右进行比对,若下一个节点不符合要求,就返回上一个节点,换一条路走。重复刚才的方法。
java代码:

class Solution {
    public boolean exist(char[][] board, String word) {
        char[] words = word.toCharArray();//将字符串word转化为字符数组
        for(int i = 0; i < board.length; i++) {//行索引i
            for(int j = 0; j < board[0].length; j++) {//列索引j
                if(dfs(board, words, i, j, 0)) {//进行深度优先搜索
                	return true;
                }
            }
        }
        return false;
    }
    boolean dfs(char[][] board, char[] word, int i, int j, int k) {//i,j分别是行列索引,设word中的索引为k
        if(i >= board.length || i < 0 || j >= board[0].length || j < 0 || board[i][j] != word[k]) {
        	return false;//越界或矩阵元素与目标字符不同
        }
        if(k == word.length - 1) {//找到目标字符
        	return true;
        }
        //开始递推
        board[i][j] = '\\0';//标记当前矩阵元素,修改为空字符,代表元素已经访问过,防止之后搜索重复访问
        //搜索下一个单元格,朝当前元素的上下左右四个方向开启下层递归,或连接,找到一条就可返回。
        boolean res = 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 res;
    }
}



第二题:剑指 Offer 13. 机器人的运动范围

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

示例 1:
输入:m = 2, n = 3, k = 1
输出:3

示例 2:
输入:m = 3, n = 1, k = 0
输出:1

提示:
1 <= n,m <= 100
0 <= k <= 20

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/ji-qi-ren-de-yun-dong-fan-wei-lcof

解题思路:

深度优先搜索: 可以理解为暴力法模拟机器人在矩阵中的所有路径。DFS 通过递归,先朝一个方向搜到底,再回溯至上个节点,沿另一个方向搜索,以此类推。
剪枝: 在搜索中,遇到数位和超出目标值、此元素已访问,则应立即返回,称之为 可行性剪枝

和上一题类似,用的依然是深度优先搜索。

java代码:

class Solution {
    int m, n, k;
    boolean[][] visited;
    public int movingCount(int m, int n, int k) {
        this.m = m; 
        this.n = n; 
        this.k = k;
        this.visited = new boolean[m][n];
        return dfs(0, 0,0,0);
    }
    public int get(int x) {
        int s = 0;
        while (x != 0) {
            s += x % 10;
            x /= 10;
        }
        return s;
    }
    public int dfs(int i, int j,int si, int sj) {//i,j 分别为行列索引.
        si = get(i);
        sj = get(j);
        if(i >= m || j >= n || k < si + sj || visited[i][j]) {//不存在,或条件不符或访问过,返回0
        	return 0;
        }
        visited[i][j] = true;//符合条件
        return 1 + dfs(i + 1, j,si ,sj) + dfs(i, j + 1, si, sj);
    }
}

第三题:剑指 Offer 34. 二叉树中和为某一值的路径

输入一棵二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径。从树的根节点开始往下一直到叶节点所经过的节点形成一条路径。

示例:
给定如下二叉树,以及目标和 target = 22,

          5
         / \\
        4   8
       /   / \\
      11  13  4
     /  \\    / \\
    7    2  5   1

返回:

[
  [5,4,11,2],
  [5,8,4,5]
]

提示:
节点总数 <= 10000

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/er-cha-shu-zhong-he-wei-mou-yi-zhi-de-lu-jing-lcof

解题思路:
二叉树的搜索问题,使用回溯法解决,包含先序遍历和路径记录两部分。
先序遍历:按照根、左、右的顺序,遍历所有节点。
路径记录:在先序遍历中,记录从根节点到当前节点的路径。将符合题意的路径加入结果列表。

java代码:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    LinkedList<List<Integer>> res = new LinkedList<>();//存路径
    LinkedList<Integer> path = new LinkedList<>(); //存路径所需节点
    public List<List<Integer>> pathSum(TreeNode root, int sum) {
        recur(root, sum);
        return res;
    }
    void recur(TreeNode root, int tar) {//递推
        if(root == null) {//节点为空时返回
        	return;
        }
        path.add(root.val);//将节点值加入路径
        tar = tar - root.val;//让目标值,从sum减到0
        if(tar == 0 && root.left == null && root.right == null){//符合条件时
            res.add(new LinkedList(path));//将路径加入res
         }
         //开始递归
        recur(root.left, tar);
        recur(root.right, tar);
        path.removeLast();//删除当前节点
    }
}

以上是关于乱序版 ● 剑指offer每日算法题打卡题解—— 搜索与回溯算法(题号12,13,34)的主要内容,如果未能解决你的问题,请参考以下文章

乱序版 ● 剑指offer每日算法题打卡题解—— 查找算法 (题号3,4,11,53)

乱序版 ● 剑指offer每日算法题打卡题解——分治算法(题号17,14)

乱序版 ● 剑指offer每日算法题打卡题解——数学 (题号39,66)

乱序版 ● 剑指offer每日算法题打卡题解——动态规划(题号19,49,60)

乱序版 ● 剑指offer每日算法题打卡题解——动态规划 (题号10,63)

乱序版 ● 剑指offer每日算法题打卡题解——栈与队列(题号59)