剑指offer 12 矩阵中的路径

该文章描述了一个Java程序,它使用深度优先搜索(DFS)算法在给定的二维字符网格中查找一个单词。程序首先初始化相关变量,然后通过遍历网格并进行DFS搜索来判断单词是否存在于网格中。搜索过程中,程序会检查当前单元格的字符是否与目标单词匹配,并沿着四个方向(上、下、左、右)继续搜索。若找到单词的最后一个字符,则返回true,否则返回false。文章还提到了一些代码优化技巧,如减少路径矩阵的使用和简化方向处理。
摘要由CSDN通过智能技术生成

题目

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

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

样例

在这里插入图片描述

思路分析

本题采用DFS进行深度搜索,如果搜索到的下一个点位,与word中对应位的值一样,那么就继续进行深度搜索
我们采用dfs中携带一个n值来表示搜索到了第几位。
采用path[][] 来表示已经被使用的路径

代码

分为思考过程冗余版本,以及优化简短版本
冗余版本:每一步拆分很细致,易懂

冗余版本

package 剑指offer.搜索与回溯.offer12;

import java.util.Arrays;

public class Solution {


    public static void main(String[] args) {

        char[][] tests = {{'A','B','C','E'},{'S','F','C','S'},{'A','D','E','E'}};
        String words = "ABCCED";



//        char[][] tests = {{'a'}};
//        String words = "a";

//        char[][] tests = {{'a','a'}};
//        String words = "aa";

//        char[][] tests = {{'C','A','A'},{'A','A','A'},{'B','C','D'}};
//        String words = "AAB";

        Solution solution = new Solution();
        boolean res = solution.exist(tests, words);

        System.out.println(res);
    }

    /**
     * 思路分析:
     * 总体思路:采用dfs or bfs 进行遍历
     * 使用深度搜索,就是使用n便是word[]的第几位
     * step1: 使用pathWord 存放符合条件数据,word[n]与遍历到的值进行比较,还需要一个char path[][]来表示以及走过的路径,初始全0,走过表示为1
     * step2:dfs下一步应该怎么走,沿着四个方向走,定义四个方向,上[-1][] 下[+1][] 左[][-1] 右[][+1] 甚至可以将移动单独抽为一个函数,并且判断是否走过重复,和是否撞墙
     *step3:结束当n == word.lenth时说明,以及遍历完了word返回true,当n周围都是已经遍历过得或者null时候就表示结束了
     *
     *
     * 代码优化:
     * path[y][x]置为0可以优化掉
     *
     * 四个方向可以优化掉
     *
     * @param board
     * @param word
     * @return
     */
    char[] words ;
    char[][] boards;
    char[][] path;
    int height;
    int width;
    public boolean exist(char[][] board, String word) {

        //定义路径变量
        height = board.length;
        width = board[0].length;
        path = new char[height][width];

//        //✅针对height =1的写法,将单独一行的进行比较即可
//        if(height == 1){
//            String oneHeight = String.valueOf(board[0]);
//
//            if(oneHeight.contains(word)){
//                return true;
//            }
//        }



        int n = 0;
        int x = 0;
        int y = 0;
        words = word.toCharArray();
        boards = board;


        //todo:找到与word[0]相同的数字进行开局
        //✅存在问题,遍历寻找需要每一个可能的都需要进行dfs
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                if(boards[i][j] == words[0]){
                    y = i;
                    x = j;

                    if(words.length == 1){
                        return true;
                    }

                    if(dfs(n,x,y)){
                        return true;
                    }
                }
            }
        }




        //[y][x]
        return false;
    }

    /**
     *
     * @param n 表示遍历了几层,表示与words[n]相对应,当n == len时,我已经把words遍历完了
     * @param x
     * @param y
     * @return
     */
    public boolean dfs(int n,int x,int y){
        //判断当前是否合适
        if(!(boards[y][x] == words[n])){
            return false;
        }

        //✅需要先判断是否合适,然后n与len-1进行比较
        if(n == words.length-1){
            return true;
        }



        //todo:将x,y列为已经可以走的
        path[y][x] = 1;


            //向上移动
        boolean canMove = canMove(x, y-1);
        if(canMove){
            boolean resPart1 = dfs(n+1,x,y-1);
            if(resPart1){
                return resPart1;
            }

        }


        //向右移动
        canMove = canMove(x+1, y);
        if(canMove){
            boolean resPart2 = dfs(n+1,x+1,y);
            if(resPart2){
                return resPart2;
            }

        }

        //向下移动
        canMove = canMove(x, y+1);
        if(canMove){
            boolean resPart3 = dfs(n+1,x,y+1);
            if(resPart3){
                return resPart3;
            }

        }
            //向左移动
        canMove = canMove(x-1, y);
        if(canMove){
            boolean resPart4 = dfs(n+1,x-1,y);
            if(resPart4){
                return resPart4;
            }

        }

        //只需要在dfs结束的时候将自己走过的放为0,每一个return false的地方置为0即可
        path[y][x] = 0;
        return false;
    }

    //判断能否这样移动,判断是否越界,判断是否已经在路径中
    public boolean canMove(int x,int y){

        //判断是否越界
        if(x < 0){
            return false;
        }
        if(x >= width){
            return false;
        }

        if(y < 0){
            return false;
        }

        if(y >= height){
            return false;
        }

        //判断是否已经走过
        if(path[y][x] == 1){
            return false;
        }

        return true;
    }

}


优化版本

package 剑指offer.搜索与回溯.offer12;

public class Improve {

    public static void main(String[] args) {
        char[][] tests = {{'A','B','C','E'},{'S','F','C','S'},{'A','D','E','E'}};
        String words = "SEE";
        Improve improve = new Improve();
        boolean res = improve.exist(tests, words);
        System.out.println(res);
    }

    /**
     * 思路分析:
     * 总体思路:采用dfs or bfs 进行遍历
     * 使用深度搜索,就是使用n便是word[]的第几位
     * step1: 使用pathWord 存放符合条件数据,word[n]与遍历到的值进行比较,还需要一个char path[][]来表示以及走过的路径,初始全0,走过表示为1
     * step2:dfs下一步应该怎么走,沿着四个方向走,定义四个方向,上[-1][] 下[+1][] 左[][-1] 右[][+1] 甚至可以将移动单独抽为一个函数,并且判断是否走过重复,和是否撞墙
     *step3:结束当n == word.lenth时说明,以及遍历完了word返回true,当n周围都是已经遍历过得或者null时候就表示结束了
     *
     *
     * 代码优化:
     * path[y][x]置为0可以优化掉
     *
     * 四个方向可以优化掉
     * 1. 通过使用directions[][] = {{-1,0},{0,1},{1,0},{0,-1}} 顺时针方向
     * 2. x = x + direction[1],y = y+direction[0]
     *
     * @param board
     * @param word
     * @return
     */
    char[] words ;
    char[][] boards;
    char[][] path;
    int height;
    int width;
    int[][] directions = {{-1,0},{0,1},{1,0},{0,-1}};
    int[] direction;
    public boolean exist(char[][] board, String word) {

        //定义路径变量
        height = board.length;
        width = board[0].length;
        path = new char[height][width];

        //定义n,x,y
        int n = 0;
        int x = 0;
        int y = 0;
        //将word和board的作用域扩大,方便调用
        words = word.toCharArray();
        boards = board;
       //优化:遍历每一个值,都进行dfs,dfs中会进行判断
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                if(dfs(n,j,i)){
                    return true;
                }
            }
        }

        return false;
    }

    /**
     *
     * @param n 表示遍历了几层,表示与words[n]相对应,当n == len时,我已经把words遍历完了
     * @param x
     * @param y
     * @return
     */
    public boolean dfs(int n,int x,int y){
        //判断当前的值是否与words需要对比的值一样,一样则继续,不一样则停止dfs
        if(!(boards[y][x] == words[n])){
            return false;
        }

        //判断是否已经将words中的每一个值都进行了遍历,已经进行完了则返回true
        if(n == words.length-1){
            return true;
        }

        //将该点位确定为已经走过
        path[y][x] = 1;

        //四个方向,进行dfs
        for (int i = 0; i < 4; i++) {
            int[] direction = directions[i];

            boolean canMove = canMove(x + direction[1], y + direction[0]);
            if(canMove){
                boolean resPart = dfs(n+1,x + direction[1],y + direction[0]);
                if(resPart){
                    return resPart;
                }
            }
        }

        //只需要在dfs结束的时候将自己走过的放为0
        path[y][x] = 0;
        return false;
    }

    //判断能否这样移动,判断是否越界,判断是否已经在路径中
    public boolean canMove(int x,int y){

        //判断是否越界
        if(x < 0){
            return false;
        }
        if(x >= width){
            return false;
        }

        if(y < 0){
            return false;
        }

        if(y >= height){
            return false;
        }

        //判断是否已经走过
        if(path[y][x] == 1){
            return false;
        }

        return true;
    }

}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值