剑指offer系列之六十四:矩阵中的路径

题目描述

请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。 例如 a b c e s f c s a d e e 矩阵中包含一条字符串”bcced”的路径,但是矩阵中不包含”abcb”路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。

这实际上是回溯法的一个应用。所谓回溯法就是按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择。具体到这道题目就是对于每个字符,如果在矩阵中找到了其在矩阵中的位置,进行下一次寻找的时候,可以从上、下、左、右四个方向(边界元素除外)进行递归寻找,如果找到了则继续寻找下一个字符;如果没有找到的话,则回到上一个字符重新寻找。直到找到全部字符在矩阵中对应的位置。下面是具体实现的代码(已被牛客AC):

public class HasPath {

    /**
     * 基本思路是创建一个布尔数组,用于记录矩阵中已经访问过的标记。 对于路径中的第i个字符,除了边界的元素外,其他位置的元素都
     * 有上、下、左、右四个相邻的位置。那么路径中的第i+1个字符可 以从这四个位置中寻找得到。依此进行递归,直到找到最后一个字符 在矩阵中的位置为止。
     *
     * @Description: TODO
     * @param @param matrix
     * @param @param rows
     * @param @param cols
     * @param @param str
     * @param @return
     * @return boolean
     * @throws
     * @author rhwayfun
     * @date Dec 21, 2015
     */
    public boolean hasPath(char[] matrix, int rows, int cols, char[] str) {
        // 创建一个布尔数组
        boolean[] visited = new boolean[matrix.length];
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                if (hasPathCore(matrix, rows, cols, i, j, 0, str, visited)) {
                    return true;
                }
            }
        }
        return false;
    }

    private boolean hasPathCore(char[] matrix, int rows, int cols, int i,
            int j, int k, char[] str, boolean[] visited) {
        // 对于给定行数和列数得到其在矩阵中的下标
        int index = i * cols + j;
        if (i < 0 || i >= rows || j < 0 || j >= cols || matrix[index] != str[k]
                || visited[index])
            return false;
        visited[index] = true;
        // 如果递归到最后一个位置的字符,则表明前面位置的字符都在矩阵中找到了对应的位置
        if (k == str.length - 1)
            return true;
        // 如果没有递归到最后一个位置的字符,则继续递归,k+1表示继续在矩阵中寻找str数组中下一个位置的字符在矩阵中的位置
        if (hasPathCore(matrix, rows, cols, i - 1, j, k + 1, str, visited)
                || hasPathCore(matrix, rows, cols, i + 1, j, k + 1, str, visited)
                || hasPathCore(matrix, rows, cols, i, j - 1, k + 1, str, visited)
                || hasPathCore(matrix, rows, cols, i, j + 1, k + 1, str, visited)) {
            return true;
        }else{
            //如果相邻格子的字符都没有匹配到下一个字符,则需要回到前一个格子,从而需要把把位置的状态重新设定为未访问
            k--;
            visited[index] = false;
        }
        return false;
    }

    public static void main(String[] args) {
        String s= "abcesfcsadee";
        String s2 = "abcb";
        char[] matrix = s.toCharArray();
        char[] str = s2.toCharArray();
        boolean b = new HasPath().hasPath(matrix, 3, 4, str);
        System.out.println(b);
    }
}
时间: 2025-01-19 16:10:05

剑指offer系列之六十四:矩阵中的路径的相关文章

剑指offer系列之六十五:机器人的运动范围

题目描述 地上有一个m行和n列的方格.一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子. 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18.但是,它不能进入方格(35,38),因为3+5+3+8 = 19.请问该机器人能够达到多少个格子? 这题实际与上一题"矩阵中的路径"思路是相似的,都是需要创建一个状态数组对访问的格子进行标记,但是这里需要计算所有能够走的格子总数,实际

剑指offer系列之五十四:按之字形顺序打印二叉树

题目描述 请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推. 此题明显是层序遍历的思路.由于需要按照之字形打印每一层,相当于在打印每一行之前需要判断上一行打印的顺序.比如,如果上一行打印的顺序使从左到右,那么下一行的打印顺序应该是从右到左.实现的这点可以采用奇数行从左到右打印,偶数行从右到左进行打印.还可直接设置 一个布尔变量,每打印一行就改变一次该变量的值.其他的就是层序遍历的思路了.下面是我实现的代

剑指offer系列之三十四:数组中的逆序对

题目描述 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数. 要找到数组中的逆序对,一种思路是每遍历到一个元素的时候就和后面的元素进行一一比较,这种算法的时间复杂度是O(n2),所以不是很理想.我们可以借鉴归并排序的思想,把数组划分为子数组,然后对每个子数组中的逆序对数进行统计,统计完成后再并到一个新的数组中进行统计,这样就化整为零,实现了高效统计.总计起来思路就是:首先把数组划分为子数组,然后统计子数组中的逆序对数,然后

剑指offer系列之四十四:翻转单词顺序

题目描述 牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上.同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思.例如,"student. a am I".后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是"I am a student.".Cat对一一的翻转这些单词顺序可不在行,你能帮助他么? 可以发现,要对一个句子进行翻转,可以先对整个句子进行翻转,之后再对每个单词进行翻转.而不论是返

剑指offer系列之十四:反转链表

题目描述 输入一个链表,反转链表后,输出链表的所有元素. 思路如下:在遍历链表上的每个节点的时候,就修改其指针,当遍历到最后一个结点的时候,整个链表就反转完成了.所以需要创建三个变量:一个是当前遍历的结点,一个是遍历结点的前一个结点,还有一个是当前遍历结点的下一个结点.基于这种思路可以写出如下的实现代码(已被牛客AC): package com.rhwayfun.offer; public class ReverseLinkedList { public static class ListNod

剑指offer系列之六十:序列化二叉树

题目描述 请实现两个函数,分别用来序列化和反序列化二叉树 首先得理解题目的意思,序列化就是返回一个带有#和逗号的字符串.反序列化就是根据带有#和逗号的字符串返回一棵二叉树.比如对于二叉树 1 / \ 2 3 /\ /\ 4 5 6 7 来讲,序列化的结果是1,2,#,#,3,4,#,7,#,#,5,#,#,.而反序列化的结果则是输出一棵二叉树. 下面是具体的实现代码(已被牛客AC): String Serialize(TreeNode root) { StringBuilder sb = new

剑指offer系列之六十二:数据流中的中位数

题目描述 如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值.如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值. 根据题目的意思,就是对数据流中的数据进行排序然后得到其中位数.要解决的关键问题是如何在读入数据的时候就对数据进行排序.实际上可以看成是插入排序算法的应用,可以维持一个List集合,保证每次读入数据集合中的数据都是排序的.基本思路是:从集合的第一个元素开始,依次比较与新读入的元素的大小关系,从而把新读入

剑指offer系列之三十:整数中1出现的次数

题目描述 求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1.10.11.12.13因此共出现6次,但是对于后面问题他就没辙了.ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数. 有一种比较简洁的思路:由于是一个整数区间,所以可以对每一个数进行判断,那么如何判断某个数中1出现了多少次呢?注意到如果一个数一直被10除,如果被10整除后的余数是1,那么一定出现了数字1.举个例子,数字11

剑指offer系列之十二:调整数组顺序使奇数位于偶数前面

题目描述 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变. 这道题第一思路自然是这样的:从头开始遍历这个数组,如果遇到偶数就把这个数之后的所有数往前移动一位,这样数组会留出一个空位,移动完毕之后把该偶数放到该空位即可.这样处理的话需要两次循环,一次是遍历,另一次是移位,所以时间复杂度是O(n2).下面是这种思路的实现代码(已被牛客AC): public void reOrd