• 79. 单词搜索


    79. 单词搜索

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

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

    示例 1:

    在这里插入图片描述

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

    示例 2:

    在这里插入图片描述

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

    示例 3:

    在这里插入图片描述

    输入:board = [[“A”,“B”,“C”,“E”],[“S”,“F”,“C”,“S”],[“A”,“D”,“E”,“E”]], word = “ABCB”
    输出:false

    提示:
    • m == board.length
    • n = board[i].length
    • 1 <= m, n <= 6
    • 1 <= word.length <= 15
    • board 和 word 仅由大小写英文字母组成

    **进阶:**你可以使用搜索剪枝的技术来优化解决方案,使其在 board 更大的情况下可以更快解决问题?

    思路:(回溯暴力搜索)

    整体思路
    使用深度优先搜索(DFS) 和回溯的思想实现。在访问过程中要设置一个二维数组标记元素 hasVisited 是否被访问过。

    外层遍历
    遍历 board 的所有元素, 并定义函数,从每个结点内层遍历,传入以下参数;

    • 变量 k 记录已经匹配的长度
    • 该节点的行 r 列 c 坐标
    • 数组的遍历情况 hasVisited
    • 原字符数组 board
    • 需要搜索的字符串 word

    内层遍历:递归 + 回溯

    • 定义递归返回条件
    • 边界情况及不符情况判断
    • 如果符合,把该节点标记为已访问
    • 再从该节点出发,从四个方向依次递归调用,并判断
    • 递归结束后,回溯,即将该节点置位未访问

    代码:(Java)

    public class words_search {
    
    	public static void main(String[] args) {
    		// TODO 自动生成的方法存根
    		char[][] board = {
    				{'A', 'B', 'C', 'E'},
    				{'S', 'F', 'C', 'S'},
    				{'A', 'D', 'E', 'E'}
    		};
    		String word = "ABCB";
    		System.out.println(exist(board, word));
    	}
    	private static int [][] dircetions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};//可有走的四个方向
    	private static int m;
    	private static int n;
    	
    	public static boolean exist(char[][] board, String word) {
    		if(word == null || word.length() == 0) {
    			return true;
    		}
    		if(board == null || board.length == 0 || board[0].length == 0) {
    			return false;
    		}
    		
    		m = board.length;//行
    		n = board[0].length;//列
    		
    		boolean [][] hasVisited = new boolean[m][n];//是否被访问
    
    		for(int r = 0; r < m; r++) {
    			for(int c = 0; c < n; c++) {
    				if(backtracking(0, r, c, hasVisited, board, word)) {//数组中的每一个字母都可以当做首字母
    					return true;
    				}
    			}
    		}
    		return false;
    	}
    
    	private static boolean backtracking(int k, int r, int c, boolean[][] hasVisited, char[][] board, String word) {
    		// TODO 自动生成的方法存根
    		if(k == word.length()) {//比对完成,返回
    			return true;
    		}
    		if(r < 0 || r >= m || c < 0 || c >= n || board[r][c] != word.charAt(k) || hasVisited[r][c]) {//边界及不符合判断
    			return false;
    		}
    		hasVisited[r][c] = true;//访问
    		for(int [] d : dircetions) {//四个方向依次遍历
    			if(backtracking(k + 1, r + d[0], c + d[1], hasVisited, board, word)){
    				return true;
    			}
    		}
    		hasVisited[r][c] = false;//回溯
    		
    		return false;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    输出:

    在这里插入图片描述

    复杂度分析:
    • 时间复杂度:一个非常宽松的上界为 O ( M N ⋅ 3 L ) O(MN⋅3^L) O(MN3L),其中 M,N为网格的长度与宽度,L 为字符串 word 的长度。在每次调用函数 backtracking 时,除了第一次可以进入 4 个分支以外,其余时间我们最多会进入 3 个分支(因为每个位置只能使用一次,所以走过来的分支没法走回去)。由于单词长为 L ,故 backtracking 的时间复杂度为 O ( 3 L ) O(3^L) O(3L),而我们要执行 O(MN)次检查。然而,由于剪枝的存在,我们在遇到不匹配或已访问的字符时会提前退出,终止递归流程。因此,实际的时间复杂度会远远小于 O ( M N ⋅ 3 L ) O(MN⋅3^L) O(MN3L)

    • 空间复杂度:O(MN)。我们额外开辟了 O(MN) 的 hasVisited 数组,同时栈的深度最大为O(min⁡(L,MN)) 。

    注:仅供学习参考!

    题目来源:力扣

  • 相关阅读:
    单片机程序无法下载?
    SentencePiece python 实战
    Netty入门——组件(Channel)一
    Java版分布式微服务云开发架构 Spring Cloud+Spring Boot+Mybatis 电子招标采购系统源码
    【Bluetooth|蓝牙开发】二、蓝牙开发入门
    wpf的GridSplitter使用
    分布式数据库难题(三):数据一致性
    Unix系统用户下载内容存放位置
    H3C AP瘦切胖配置
    uniapp 扫码功能
  • 原文地址:https://blog.csdn.net/weixin_43412762/article/details/128131522