当前位置: 首页 > news >正文

矩阵中的路径 -- java

题目描述

请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。

例如下面的矩阵包含了一条 bfce 路径。但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。

在这里插入图片描述

题目考点

  • 考察应聘者对回溯法的理解。通常在二维矩阵上找路径这类问题都可以应用回溯法解决。
  • 考察应聘者对数组的编程能力。我们一般都把矩阵看成一个二维数组。只有对数组的特性充分了解,才有可能快速、正确地实现回溯法的代码。

解题思路

这是一个可以用回溯法(见补充)解决的典型题。

首先,在矩阵中任选一个格子作为路径的起点。

由于回溯法的递归特性,路径可以被看成一个栈。当在矩阵中定位了路径中前n个字符的位置之后,在与第n个字符对应的格子的周围都没有找到第n+1个字符,这个时候只要在路径上回到第n-1个字符,重新定位第n个字符。一直重复这个过程,直到路径字符串上所有字符都在矩阵中找到合适的位置。

由于路径不能重复进入矩阵的格子,还需要定义和字符矩阵大小一样的布尔值矩阵,用来标识路径是否已经进入每个格子。

代码

public class HasPath {
    /**
     * 判断矩阵中是否存在存在一条包含str所有字符的路径
     * @param matrix
     * @param rows
     * @param cols
     * @param str
     * @return
     */
    public static boolean hasPath(char[] matrix, int rows, int cols, char[] str) {
        // 防止特殊测试用例
        if (matrix == null || matrix.length == 0 || rows < 1 || cols < 1 || str == null || str.length == 0) {
            return false;
        }

        // 定义布尔值矩阵(虽然是一个布尔值数组)
        boolean[] visited = new boolean[rows * cols];

        // 定义走到字符串的第几个字符
        int pathLength = 0;

        for (int row = 0; row < rows; row++) {
            for (int col = 0; col < cols; col++) {
                if (hasPathCore(matrix, rows, cols, row, col, str, pathLength, visited)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 寻找一条路
     * @param matrix
     * @param rows
     * @param cols
     * @param row 当前元素行
     * @param col 当前元素列
     * @param str
     * @param pathLength 走到字符串的第几个字符
     * @param visited
     * @return
     */
    public static boolean hasPathCore(char[] matrix, int rows, int cols, int row, int col, char[] str, int pathLength,
                                      boolean[] visited) {
        // 因为pathLength从0开始,所以当它等于str长度说明已经找到
        if (pathLength == str.length) {
            return true;
        }
        // 定义是否有路
        boolean hasPath = false;
        if (row >= 0 && row < rows && col >= 0 && col < cols
                && matrix[row * cols + col] == str[pathLength]
                && !visited[row * cols + col]) {
            // 继续走
            pathLength++;
            visited[row * cols + col] = true;
            
            // 递归下去(上下右左都看一遍)
            hasPath = hasPathCore(matrix, rows, cols, row, col-1, str, pathLength, visited)
                    || hasPathCore(matrix, rows, cols, row-1, col, str, pathLength, visited)
                    || hasPathCore(matrix, rows, cols, row, col+1, str, pathLength, visited)
                    || hasPathCore(matrix, rows, cols, row+1, col, str, pathLength, visited);
            if (!hasPath) {
                // 回溯
                visited[row * cols + col] = false;
            }
        }

        return hasPath;
    }

    // 测试
    public static void main(String[] args) {
        char[] matrix = new char[] {'a', 'b', 't', 'g', 'c', 'f', 'c', 's', 'j', 'd', 'e', 'h'};
        char[]  str = new char[] {'b', 'f', 'c', 'e'};
        char[]  strFalse = new char[] {'a', 'b', 'f', 'b'};
        System.out.println(hasPath(matrix,3,4,str));
        System.out.println(hasPath(matrix,3,4,strFalse));
    }
}

当矩阵中坐标为(row,col)的格子和路径字符串中下标为pathLength的字符一样时,从4个相邻的格子(row,col-1),(row-1,col),(row,col+1)以及(row+1,col)中去定位路径字符串中下标为pathLength+1的字符。

如果4个相邻的格子都没有匹配字符串中下标为pathLength+1的字符,表明当前路径字符串中下标为pathLength的字符在矩阵中的定位不正确,我们需要回到前一个字符(pathLength-1),然后重新定位。

一直重复这个过程,直到路径字符串上所有字符都在矩阵中找到合适的位置

补充

回溯法:

回溯法可以看成蛮力法的升级版,它非常适合由多个步骤组成的问题,并且每个步骤都有多个选项,当我们在某一步选择了其中一个选项时,就进行下一步,如果下一步不行不符合条件,则回溯到之前那一步,不然则继续选择一个选项进行下一步,就这样重复选择,直至到达最终的状态。


来自:
《剑指Offer》
Coding-Interviews/矩阵中的路径.md at master · todorex/Coding-Interviews

相关文章:

  • 机器人的运动范围 -- java
  • pr字幕一个一个出现的笨方法
  • 绿色版premiere cs4无法导出(输出)解决方法
  • ip被禁止后访问网页403 易语言
  • Ext.String.format 的作用
  • 剪绳子 -- java
  • 二进制中1的个数 -- java
  • mysql 5.7修改root登录密码
  • 关于 Double.compare()
  • mac关闭f11显示桌面快捷键
  • java中如何比较两个浮点型大小
  • 了解 BigDecimal.valueOf(double val)与new BigDecimal(double val) 的区别
  • 数值的整数次方 -- java
  • Could not get a resource from the pool 的原因之一
  • 打印从1到最大的n位数 -- java
  • 网络传输文件的问题
  • [译] 理解数组在 PHP 内部的实现(给PHP开发者的PHP源码-第四部分)
  • 【EOS】Cleos基础
  • 【MySQL经典案例分析】 Waiting for table metadata lock
  • CentOS学习笔记 - 12. Nginx搭建Centos7.5远程repo
  • Joomla 2.x, 3.x useful code cheatsheet
  • Laravel Telescope:优雅的应用调试工具
  • React-redux的原理以及使用
  • RedisSerializer之JdkSerializationRedisSerializer分析
  • 测试开发系类之接口自动化测试
  • 分类模型——Logistics Regression
  • 给第三方使用接口的 URL 签名实现
  • 蓝海存储开关机注意事项总结
  • 你真的知道 == 和 equals 的区别吗?
  • 前端技术周刊 2019-01-14:客户端存储
  • 使用Tinker来调试Laravel应用程序的数据以及使用Tinker一些总结
  • 优化 Vue 项目编译文件大小
  • 06-01 点餐小程序前台界面搭建
  • media数据库操作,可以进行增删改查,实现回收站,隐私照片功能 SharedPreferences存储地址:
  • 策略 : 一文教你成为人工智能(AI)领域专家
  • ​​​​​​​Installing ROS on the Raspberry Pi
  • ​软考-高级-系统架构设计师教程(清华第2版)【第9章 软件可靠性基础知识(P320~344)-思维导图】​
  • # 数据结构
  • (2022 CVPR) Unbiased Teacher v2
  • (超简单)构建高可用网络应用:使用Nginx进行负载均衡与健康检查
  • (附源码)流浪动物保护平台的设计与实现 毕业设计 161154
  • (经验分享)作为一名普通本科计算机专业学生,我大学四年到底走了多少弯路
  • (转)【Hibernate总结系列】使用举例
  • .Net 4.0并行库实用性演练
  • .Net 6.0 处理跨域的方式
  • .net core 源码_ASP.NET Core之Identity源码学习
  • .NET 解决重复提交问题
  • .NET/C# 在 64 位进程中读取 32 位进程重定向后的注册表
  • .net6解除文件上传限制。Multipart body length limit 16384 exceeded
  • .net反混淆脱壳工具de4dot的使用
  • .NET企业级应用架构设计系列之应用服务器
  • @ModelAttribute注解使用
  • @Tag和@Operation标签失效问题。SpringDoc 2.2.0(OpenApi 3)和Spring Boot 3.1.1集成
  • @vue/cli脚手架
  • [BZOJ1008][HNOI2008]越狱