剑指Offer:矩阵中的路径Java/Python

1.题目描述

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

2.算法描述

方法:回溯法

在 矩 阵 中 任 选 一 个 格 子 作 为 路 径 的 起 点 。 在矩阵中任选一个格子作为路径的起点。
如 果 探 索 的 路 径 上 的 第 i 个 字 符 不 是 c h , 那 么 这 个 格 子 不 可 能 处 在 真 正 路 径 上 的 第 i 个 位 置 。 \red{如果探索的路径上的第i个字符不是ch,那么这个格子不可能处在真正路径上的第i个位置。} ichi
如 果 探 索 的 路 径 上 的 第 i 个 字 符 正 好 是 c h , 那 么 往 相 邻 的 格 子 寻 找 真 正 路 径 上 的 第 i + 1 个 字 符 。 \red{如果探索的路径上的第i个字符正好是ch,那么往相邻的格子寻找真正路径上的第i+1个字符。} ichi+1
除 在 矩 阵 边 界 上 的 格 子 之 外 , 其 他 格 子 都 有 4 个 相 邻 的 格 子 。 除在矩阵边界上的格子之外,其他格子都有4个相邻的格子。 4
重 复 这 个 过 程 直 到 路 径 上 的 所 有 字 符 都 在 矩 阵 中 找 到 相 应 的 位 置 。 重复这个过程直到路径上的所有字符都在矩阵中找到相应的位置。

具体地:

1. 初 始 化 一 个 与 矩 阵 大 小 相 等 的 f l a g 变 量 , 初 始 化 为 0 , 标 识 探 索 的 元 素 是 否 占 用 , 未 占 用 为 0 , 占 用 标 识 为 1 。 1.初始化一个\red{与矩阵大小相等的flag变量,初始化为0},标识探索的元素是否占用,未占用为0,占用标识为1。 1.flag001
2. 初 始 化 一 个 变 量 k 为 0 , 表 示 从 指 定 路 径 的 第 0 个 字 符 开 始 探 索 。 2.初始化一个\red{变量k为0},表示从指定路径的第0个字符开始探索。 2.k00
3. 以 矩 阵 中 的 每 一 个 元 素 为 起 始 点 , 假 设 起 始 点 坐 标 ( 矩 阵 坐 标 ) 为 i , j , 进 入 递 归 调 用 : 3.以矩阵中的每一个元素为起始点,假设起始点坐标(矩阵坐标)\red{为i,j},进入递归调用: 3.i,j
    若 i , j 不 在 合 理 范 围 , 或 探 索 的 元 素 已 经 被 占 用 , 或 探 索 的 元 素 与 路 径 中 元 素 不 等 , 则 探 索 的 路 径 走 不 通 返 回 f a l s e 。 \red{\ \ \ 若i,j不在合理范围,或探索的元素已经被占用,或探索的元素与路径中元素不等,则探索的路径走不通返回false。}    i,jfalse
    若 k 已 经 到 达 路 径 的 最 后 一 个 元 素 , 则 从 矩 阵 中 探 索 到 一 条 与 指 定 路 径 相 同 的 路 径 , 返 回 t r u e 。 \red{\ \ \ 若k已经到达路径的最后一个元素,则从矩阵中探索到一条与指定路径相同的路径,返回true。}    ktrue
    把 i , j 的 标 识 更 改 为 1 , 标 识 占 用 。 \red{\ \ \ 把i,j的标识更改为1,标识占用。}    ij1
    探 索 以 i , j 为 新 起 始 点 开 始 往 上 、 下 、 左 、 右 四 个 方 向 是 否 存 在 路 径 。 \red{\ \ \ 探索以i,j为新起始点开始往上、下、左、右四个方向是否存在路径。}    ij
    把 i , j 的 标 识 更 改 为 0 , 回 溯 , 标 识 未 占 用 。 \red{\ \ \ 把i,j的标识更改为0,回溯,标识未占用。}    ij0

3.代码描述

3.1.Java代码

public class Solution {
    public boolean hasPath(char[] matrix, int rows, int cols, char[] str){
        int[] flag = new int[matrix.length];//用同等大小的标志变量标识矩阵中元素是否被占用 不能回头走
        //对每一个可能的起始点开始递归
        for(int i=0;i<rows;i++)
            for(int j=0;j<cols;j++)
                if(helper(matrix, str, flag, rows, cols, i, j, 0) == true)
                    return true;
        return false;
    }
    private boolean helper(char[] matrix, char[] str, int[] flag, int rows, int cols, int i, int j, int k){
        int index = cols * i + j;
        //越界不行  当前元素已经被占用不行  当前元不等于路径元素不行
        if(i<0 || i>=rows || j<0 || j>=cols || flag[index]==1 || matrix[index]!=str[k]) return false;
        //只用确切地扫描到了路径的尾部 就是找到了路径
        if(k == str.length-1) return true;
        //当前元素标识为占用
        flag[index] = 1;
        if(helper(matrix, str, flag, rows, cols, i-1, j, k+1)||
           helper(matrix, str, flag, rows, cols, i+1, j, k+1)||
           helper(matrix, str, flag, rows, cols, i, j-1, k+1)||
           helper(matrix, str, flag, rows, cols, i, j+1, k+1))
            return true;
        //如果上述没有返回true  回溯把标识换回来 
        flag[index] = 0;
        return false;
    }

}

3.2.Python代码

# -*- coding:utf-8 -*-
class Solution:
    def hasPath(self, matrix, rows, cols, path):
        flag = [0] * len(matrix)
        for i in range(rows):
            for j in range(cols):
                if self.helper(matrix, path, flag, rows, cols, i, j, 0)==True:
                    return True
        return False
    def helper(self, matrix, path, flag, rows, cols, i, j, k):
        idx = i * cols + j
        if i<0 or i>=rows or j<0 or j>=cols or flag[idx]==1 or matrix[idx]!=path[k]:
            return False
        if k == len(path)-1:
            return True
        flag[idx] = 1
        if (self.helper(matrix, path, flag, rows, cols, i-1, j, k+1)
           or self.helper(matrix, path, flag, rows, cols, i+1, j, k+1)
           or self.helper(matrix, path, flag, rows, cols, i, j-1, k+1)
           or self.helper(matrix, path, flag, rows, cols, i, j+1, k+1)):
            return True
        else:
            flag[idx] = 0
            return False
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值