剑指offer-矩阵中的路径

汇总:剑指offer算法合集

题目

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

例如,在下面的 3×4 的矩阵中包含单词 “ABCCED”(单词中的字母已标出)。

在这里插入图片描述

示例 1:

输入:board = [[“A”,“B”,“C”,“E”],[“S”,“F”,“C”,“S”],[“A”,“D”,“E”,“E”]], word = “ABCCED”
输出:true
示例 2:

输入:board = [[“a”,“b”],[“c”,“d”]], word = “abcd”
输出:false

提示:

1 <= board.length <= 200
1 <= board[i].length <= 200
board 和 word 仅由大小写英文字母组成

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/ju-zhen-zhong-de-lu-jing-lcof

解题思路

  • 由于二维数组每个位置都可能是目标字符串第0个字符对应的起点,因此只能遍历二维数组,把每个位置作为起点进行查找目标字符串
  • 确定起点后,下一步可走的方向有四个,之后每一步可走方向只有三个,因为有一个方向是上次走来的方向,但我们不知道上一次走来的方向,因此依然会在每个位置的四个方向都尝试
  • 走过的位置用一个非字母的字符占位,表示当前位置不可重复走过。但如果尝试后面的方向突然走不通了,需要回溯,回溯后需要重新把原来的字母放回原位置上
  • 每次只尝试一个方向,直到走不通就回溯,再尝试走别的方向,全部走过的位置的所有方向都试过了都走不通,说明当前起点是错误的,因此需要寻找下一个起点,然后重复前面寻找下一步的步骤。如果在走的过程中发现走过的长度已经等于目标字符串的长度,则直接返回true,说明找到了目标字符串

复杂度分析

二维数组遍历,时间复杂度为O(mn),而每个起点继续深度搜索,其中有一个方向已走过,必定走不通,因此只有三个方向是真正需要走的,而每个方向可能需要走差不多等于目标字符串长度的路,假设目标字符串长度为k,则这里的时间复杂度为O(3k),总的时间复杂度为O(3kmn)。而空间方面主要是递归k的深度,所以正常情况下是O(k),在极端的情况下需要递归mn的深度,此时空间复杂度为O(mn)

代码实现

class Solution {
    public boolean exist(char[][] board, String word) {
        //把字符串先转char数组,可以加快访问
        char[] cword = word.toCharArray();
        //遍历二维数组找起点
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[i].length; j++) {
                //检查每个起点是否能找到目标字符串
                if (check(i, j, 0, board, cword)) {
                    return true;
                }
            }
        }
        return false;
    }

    boolean check(int i, int j, int k, char[][] board, char[] word) {
        //到达边界或者当前位置的字母和目标字符串的字母不对应,则中断查找
        if (i >= board.length || i < 0 || j >= board[i].length
                || j < 0 || board[i][j] != word[k]) return false;
        //如果当前找到的路径和目标字符串一致了,说明找到了
        if (k == word.length - 1) return true;
        int kk = k + 1;
        //把走过的位置置为空,代表已经走过了
        board[i][j] = ' ';
        boolean isExist = check(i + 1, j, kk, board, word) || check(i - 1, j, kk, board, word)
                || check(i, j + 1, kk, board, word) || check(i, j - 1, kk, board, word);
        //回溯回来后,把之前置为空的位置还原
        //能走到这里说明原来位置的字母等于目标字符串第k个字母
        //所以直接把目标字符串第k个字母放回去即可
        board[i][j] = word[k];
        return isExist;
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Nbin_Newby

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值