算法准备-4.12

算法准备-4.12

1. 矩阵中的路径

  1. 描述:请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。例如,在下面的3×4的矩阵中包含一条字符串“bfce”的路径(路径中的字母用加粗标出)。

    [[“a”,“b”,“c”,“e”],
    [“s”,“f”,“c”,“s”],
    [“a”,“d”,“e”,“e”]]

    但矩阵中不包含字符串“abfb”的路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入这个格子。

  2. 思路:首先要把字符串转化为字符数组,检查第一个字符在矩阵中的位置,保存其横纵坐标,创建一个与输入矩阵同宽高的矩阵,初始值为0,每遍历一个,对应坐标的值变为1,检查他与字符串中对应的字符,相同则继续递归调用,不同则返回

  3. 题解:

    class Solution {
        public boolean exist(char[][] board, String word) {
            char[] wordarray=word.toCharArray();
            for(int i=0;i<board.length;i++)
            {
                for(int j=0;j<board[0].length;j++)
                {
                    if(dfs(board,wordarray,i,j,0))
                    {
                        return true;
                    }
                }
            }
            return false;
        }
        public boolean dfs(char[][] board,char[] wordarray,int i,int j,int k){
            if(i>=board.length||i<0||j<0||j>=board[0].length||wordarray[k]!=board[i][j])
            {
                return false;
            }
            if(k==wordarray.length-1)
            {
                return true;
            }
            char temp=board[i][j];
            board[i][j]='/';
            boolean res=dfs(board,wordarray,i+1,j,k+1)||dfs(board,wordarray,i,j+1,k+1)||dfs(board,wordarray,i-1,j,k+1)||dfs(board,wordarray,i,j-1,k+1);
            board[i][j]=temp;
            return res;
        }
    }
    

    注:这里面检测已走过的路径是将char矩阵中的额值变为/,不可能和字符相等,也可以用多一个数组来存储

    class Solution {
        public boolean exist(char[][] board, String word) {
            char[] wordarray=word.toCharArray();
            int[][] flag=new int[board.length][board[0].length];
            for(int i=0;i<board.length;i++)
            {
                for(int j=0;j<board[0].length;j++)
                {
                    if(dfs(board,wordarray,i,j,0,flag))
                    {
                        return true;
                    }
                }
            }
            return false;
        }
        public boolean dfs(char[][] board,char[] wordarray,int i,int j,int k,int[][] flag){
            if(i>=board.length||i<0||j<0||j>=board[0].length||wordarray[k]!=board[i][j]||flag[i][j]==1)
            {
                return false;
            }
            if(k==wordarray.length-1)
            {
                return true;
            }
            flag[i][j]=1;
            boolean res=dfs(board,wordarray,i+1,j,k+1,flag)||dfs(board,wordarray,i,j+1,k+1,flag)||dfs(board,wordarray,i-1,j,k+1,flag)||dfs(board,wordarray,i,j-1,k+1,flag);
            flag[i][j]=0;
            return res;
        }
    }
    

    这两段代码的区别就在于检测走过的路径方法差异,其余的思路一致

  4. 反省:这题之前卡住的地方在于想要先找出第一个字符在矩阵中的位置,忽略了与其后操作的统一性

2. 机器人的运动范围

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

  2. 思路:这一题和上题“矩阵中的路径”相似,不需要比较字符串,只多了一个比较数位,单独写一个计算数位的函数即可

  3. 题解:

    class Solution {
        public int movingCount(int m, int n, int k) {
            int[][] flag=new int[m][n];//创建一个同宽高的数组记录是否到达过
            return count(m,n,0,0,k,flag);
        }
    
        public int plus(int m,int n){//计算数位之和
            int res=0;
            while(m!=0)
            {
                int temp=m%10;
                res+=temp;
                m=m/10;
            }
            while(n!=0)
            {
                int temp=n%10;
                res+=temp;
                n=n/10;
            }
            return res;
        }
    
        public int count(int m,int n,int i,int j,int k,int[][] flag){
            if(i<0||j<0||i>=m||j>=n||plus(i,j)>k||flag[i][j]==1)
            {
                return 0;
            }
            flag[i][j]=1;
            return 1+count(m,n,i-1,j,k,flag)+count(m,n,i,j+1,k,flag)+count(m,n,i+1,j,k,flag)+count(m,n,i,j-1,k,flag);
        }
    }
    
  4. 优化:

    1. 数位之和计算简化:当(x+1)%10=0时,其数位之和比下一个多8,其他情况少1

      用公式表示的话就是这样:(x + 1) % 10 != 0 ? s_x + 1 : s_x - 8

      注:s_x表示x的数位和

    2. 搜索方向的简化:

      在这里插入图片描述

      图片转载自leetcode

      由上图可知,只通过向右和向下移动可到达所有的可达点,机器人只需要向右移动或者向下移动

    3. 优化解:

      class Solution {
          int m,n,k;
          int[][] flag;
          public int movingCount(int m, int n, int k) {
              this.m=m;
              this.n=n;
              this.k=k;
              this.flag=new int[m][n];
              return dfs(0,0,0,0);
          }
          public int dfs(int i,int j,int si,int sj){
              if(i>=m||j>=n||flag[i][j]==1||k<si+sj)
              {
                  return 0;
              }
              flag[i][j]=1;
              return 1+dfs(i+1,j,(i+1)%10==0?si-8:si+1,sj)+dfs(i,j+1,si,(j+1)%10==0?sj-8:sj+1);
          }
      }
      

      优化完搜索方向后,时间和空间的效率都优化了

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值