2021.02.07 矩阵中的路径

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

  • 1 <= board.length <= 200
  • 1 <= board[i].length <= 200

  • 思路:

本质上就是深度有限搜索。设置两个全局变量word(String)、tag(boolean[][] 记录是否已经访问过),然后遍历二维矩阵中的每个元素,以目前元素为起点,查看是否存在路径,若是存在则直接返回true,遍历结束后若是不存在则直接返回false。

  • 算法过程:

hasPath(row, col, length, board):用于判断是否含有路径,row、col表示要比较字符所处的行、列,length表示要比较字符在字符串中的索引值。
若length == word.length(),表示已比对完毕,存在路径。
否则在row、col的值合法、board[row][col] == word.charAt(length)、board[row][col]未被访问的情况下,length+1,继续判断该位置的上下左右四个方向是否存在剩下的路径,用has记录判断结果,若不存在剩下的路径,则回退,最后返回has。
大佬改进版本则直接省去了tag标记数组。

  • 自己的菜鸡代码: ```java class Solution { private boolean[][] tag; private String word; public boolean exist(char[][] board, String word) {

    1. if(board.length == 0 || word.length() == 0) return false;
    2. //自动初始化为false
    3. this.tag = new boolean[board.length][board[0].length];
    4. this.word = word;
    5. for(int i = 0; i < board.length; i++){
    6. for(int j = 0; j < board[0].length; j++){
    7. if(hasPath(i, j, 0, board)){
    8. return true;
    9. }
    10. }
    11. }
    12. return false;

    }

    boolean hasPath(int row, int col, int length, char[][] board){

    1. // 判断是否存在路径
    2. if(length == word.length()) return true;
    3. boolean has = false;
    4. if(row >= 0 && row < board.length && col >= 0 && col < board[0].length && word.charAt(length) == board[row][col]
    5. && !tag[row][col]){
    6. ++length;
    7. tag[row][col] = true;
    8. has = hasPath(row, col-1, length, board) || hasPath(row, col+1, length, board)
    9. || hasPath(row-1, col, length, board) || hasPath(row+1, col, length, board);
    10. if(!has){
    11. // 回退
    12. --length;
    13. tag[row][col] = false;
    14. }
    15. }
    16. return has;

    } }

// 大佬改进版本的

  1. - 运行结果:
  2. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/1584832/1612669336367-12bc67be-b571-44e3-8dd6-548229da04f9.png#align=left&display=inline&height=289&margin=%5Bobject%20Object%5D&name=image.png&originHeight=459&originWidth=628&size=28649&status=done&style=none&width=395)
  3. <a name="clwS3"></a>
  4. ### 2021.02.07 机器人的运动范围
  5. 今日题目:地上有一个mn列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/1584832/1612686996194-9e75bcf8-9ef9-4eb6-9c4b-0e1de93adeb7.png#align=left&display=inline&height=105&margin=%5Bobject%20Object%5D&name=image.png&originHeight=113&originWidth=253&size=2779&status=done&style=none&width=235)![image.png](https://cdn.nlark.com/yuque/0/2021/png/1584832/1612687008927-a2531495-487a-44a8-82f2-03f6d5c87076.png#align=left&display=inline&height=100&margin=%5Bobject%20Object%5D&name=image.png&originHeight=113&originWidth=260&size=2896&status=done&style=none&width=231)<br />提示:
  6. - 1 <= n,m <= 100
  7. - 0 <= k <= 20
  8. - 思路:这题也是用深度优先搜索的方法。
  9. 算法过程:
  10. - countPath(int row, int col) :用于递归计算路径长度
  11. 检查rowcol值是否符合要求,若是不符合则返回0;否则返回 1+ 上下左右的可达路径长度。
  12. - check(int row, int col):用于检查rowcol的值是否符合要求。
  13. value来记录每次的数位之和。<br />不符合的情况:row < 0 || row >= rows || col < 0 || col >= colsvalue > k。返回false。<br />符合的话则返回true
  14. - 自己的菜鸡代码:
  15. ```java
  16. class Solution {
  17. private boolean[][] tag;
  18. private int k;
  19. private int rows;
  20. private int cols;
  21. public int movingCount(int m, int n, int k) {
  22. this.tag = new boolean[m][n];
  23. this.k = k;
  24. this.rows = m;
  25. this.cols = n;
  26. return countPath(0, 0);
  27. }
  28. int countPath(int row, int col){
  29. // 用于计算路径长度
  30. int count = 0;
  31. if(check(row,col)){
  32. tag[row][col] = true;
  33. count = 1 + countPath(row, col+1) + countPath(row, col-1) + countPath(row+1, col) + countPath(row-1, col);
  34. }
  35. return count;
  36. }
  37. boolean check(int row, int col){
  38. if(row < 0 || row >= rows || col < 0 || col >= cols) return false;
  39. int value = row / 10 + row % 10 + col / 10 + col % 10;
  40. if(value <= k && !tag[row][col]) return true;
  41. return false;
  42. }
  43. }
  • 运行结果:

image.png

2021.01.22 二叉树中和为某一值的路径(思路还没写)

今日题目:输入一棵二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径。从树的根节点开始往下一直到叶节点所经过的节点形成一条路径。
image.pngimage.png
提示:节点总数 <= 10000

  • 思路:这题也好烦555。
  • 自己的菜鸡代码:

    1. /**
    2. * Definition for a binary tree node.
    3. * public class TreeNode {
    4. * int val;
    5. * TreeNode left;
    6. * TreeNode right;
    7. * TreeNode(int x) { val = x; }
    8. * }
    9. */
    10. class Solution {
    11. private LinkedList<List<Integer>> lists = new LinkedList<>();
    12. private LinkedList<Integer> list = new LinkedList<>();
    13. public List<List<Integer>> pathSum(TreeNode root, int sum) {
    14. // 本质上是先序遍历
    15. dfs(root, sum);
    16. return lists;
    17. }
    18. void dfs(TreeNode root, int sum){
    19. // 怎么回溯
    20. if(root == null) return;
    21. list.add(root.val);
    22. sum -= root.val;
    23. if(root.left == null && root.right == null && sum == 0){
    24. lists.add(new LinkedList<>(list));
    25. }
    26. dfs(root.left, sum);
    27. dfs(root.right, sum);
    28. list.removeLast();
    29. }
    30. }
  • 运行结果:

image.pngimage.pngimage.png

2021.02.18 字符串的排列

今日题目:输入一个字符串,打印出该字符串中字符的所有排列。你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。
image.png
限制:1 <= s 的长度 <= 8

  • 思路:(回溯法)分为两步,第一步是将字符串的第一个字符与后边的字符逐个交换;第二步是固定第一个字符,将后边的部分作为一个字符串整体继续进行相同的操作,很明显就是递归。第三步就是将现第一个字符与原第一个字符交换,即恢复到原来(回溯)。

需要注意的地方:
因为字符串中可能会出现的字符,所以要进行去重操作,设立一个HashSet用于该字符串中已经当过第一个字符的字符,当在每一层的字符串第一个结点与后边相交换时,检查HashSet中是否已经包含后边待交换的字符,若已包含,则直接跳过。

  • 自己的菜鸡代码:

    1. class Solution {
    2. private List<String> res = new ArrayList<>();;
    3. private char[] s;
    4. public String[] permutation(String s) {
    5. this.s = s.toCharArray();
    6. dfs(0);
    7. return res.toArray(new String[res.size()]);
    8. }
    9. void dfs(int cur){
    10. if(cur == s.length - 1){
    11. res.add(String.valueOf(s));
    12. }else{
    13. HashSet<Character> set = new HashSet<>();
    14. for(int i = cur; i < s.length; i++){
    15. if(set.contains(s[i])) continue;
    16. set.add(s[i]);
    17. char temp = s[cur];
    18. s[cur] = s[i];
    19. s[i] = temp;
    20. dfs(cur + 1);
    21. // 再交换回来
    22. temp = s[cur];
    23. s[cur] = s[i];
    24. s[i] = temp;
    25. }
    26. }
    27. }
    28. }
  • 运行结果:

image.png