题目描述

题目:79. 单词搜索

解题思路

遍历

首先找重复性,题目说给定单词是否存在于二维数组中,可以简化为从 (x, y) 走 n 步(n 表示单词长度),查看给定单词是否存在。然后再遍历二维数组里的所有点,看是否存在给定单词。

func exist(board [][]byte, word string) bool {
for x:=0;x<n;x++ {
for y:=0;y<m;y++ {
if dfs(x, y, 0) {
return true
}
}
}
return false
}

回溯

从 (x, y) 走 n 步,每一步都可以从上下左右四个方向“试探步”,直到走完 n 步,然后再比较“走过的路径” 和给定单词是否相等。

func backtrack(x int, y int, index int, s *[]byte) {
// 终止条件:走完 n 步
if index == len(word) {
return string(s) == word
}
if !visited[x][y] {
visited[x][y] = true
s = append(s, board[x][y]) for i:=0;i<direction;i++ {
newX, newY := x+direction[i][0], y+direction[i][1]
if backtrack(newX, newY, index+1) {
return true
}
} s = s[:len(s)]
visited[x][y] = false
}
return false
}

此代码存在问题,没有考虑边界的问题,当向上下左右移动时,不能超过边界,因此代码调整为:

func backtrack(x int, y int, index int, s *[]byte) {
// 终止条件:走完 n 步
if index == len(word) {
return string(s) == word
}
if !visited[x][y] {
visited[x][y] = true
s = append(s, board[x][y]) for i:=0;i<direction;i++ {
newX, newY := x+direction[i][0], y+direction[i][1]
if inArea(newX, newY) && backtrack(newX, newY, index+1) {
return true
}
} s = s[:len(s)]
visited[x][y] = false
}
return false
} func inArea(x int, y int) bool {
return x < n && x >= 0 && y < m && y >= 0
}

剪枝

上面的代码可以进一步优化,在回溯过程中,可以预先判断结果,假如走到第 i 步时,此时的字符与给定单词的第 i 位字符不相等,则可以剪掉后续的比较,即剪掉分支。

注:回溯、dfs 本质上是递归,函数调用的过程会生成一颗递归树。

func backtrack(x int, y int, index int) bool {
if index == len(word)-1 {
return board[x][y] == word[index]
} if board[x][y] == word[index] {
visited[x][y] = true
// 遍历四个方向
for i := 0; i < len(direction); i++ {
newX, newY := x+direction[i][0], y+direction[i][1]
if inArea(newX, newY) && !visited[newX][newY] {
if backtrack(newX, newY, index+1) {
return true
}
}
}
visited[x][y] = false
} return false
} func inArea(x int, y int) bool {
return x < n && x >= 0 && y < m && y >= 0
}

代码实现

var direction = [][]int{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}
var visited [][]bool
var n, m int func exist(board [][]byte, word string) bool {
n = len(board)
if n == 0 {
return false
}
m = len(board[0])
if m == 0 {
return false
}
visited = make([][]bool, n)
for i := 0; i < n; i++ {
visited[i] = make([]bool, m)
} for x := 0; x < n; x++ {
for y := 0; y < m; y++ {
if backtrack(board, word, 0, x, y) {
return true
}
}
}
return false
} func backtrack(board [][]byte, word string, index int, x int, y int) bool {
if index == len(word)-1 {
return board[x][y] == word[index]
} if board[x][y] == word[index] {
visited[x][y] = true
// 遍历四个方向
for i := 0; i < len(direction); i++ {
newX, newY := x+direction[i][0], y+direction[i][1]
if inArea(newX, newY) && !visited[newX][newY] {
if backtrack(board, word, index+1, newX, newY) {
return true
}
}
}
visited[x][y] = false
} return false
} func inArea(x int, y int) bool {
return x < n && x >= 0 && y < m && y >= 0
}

复杂度分析:

  • 时间复杂度:O(n * m * L),其中 n, m, L 分别表示二维数组的行、列和给定单词的长度。

    • 最好情况,遍历二维数组第一个元素,且走一次就找到。
    • 最坏情况,要遍历到二维数组的最后一个元素,并且各个方向都走完后,没找到结果。
  • 空间复杂度:O(n * m),其中 n, m 分别表示二维数组的行、列。只需要一个二维数组记录是否访问过元素。

总结

  • 对于类似排列、组合的问题,第一时间要想到可以使用dfs、回溯来解决。
  • 一般来说,回溯和剪枝是一起使用的,在优化时间复杂度时,记得考虑剪枝。

[LeetCode题解]79. 单词搜索的更多相关文章

  1. Leetcode题目79.单词搜索(回溯+DFS-中等)

    题目描述: 给定一个二维网格和一个单词,找出该单词是否存在于网格中. 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格.同一个单元格内的字母不允许 ...

  2. Leetcode之回溯法专题-79. 单词搜索(Word Search)

    Leetcode之回溯法专题-79. 单词搜索(Word Search) 给定一个二维网格和一个单词,找出该单词是否存在于网格中. 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元 ...

  3. Java实现 LeetCode 79 单词搜索

    79. 单词搜索 给定一个二维网格和一个单词,找出该单词是否存在于网格中. 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中"相邻"单元格是那些水平相邻或垂直相邻的单元格. ...

  4. Leetcode 79.单词搜索

    单词搜索 给定一个二维网格和一个单词,找出该单词是否存在于网格中. 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中"相邻"单元格是那些水平相邻或垂直相邻的单元格.同一个单 ...

  5. [LeetCode] 79. 单词搜索(DFS,回溯)

    题目 给定一个二维网格和一个单词,找出该单词是否存在于网格中. 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中"相邻"单元格是那些水平相邻或垂直相邻的单元格.同一个单元格 ...

  6. LeetCode 79.单词搜索 - JavaScript

    题目描述:给定一个二维网格和一个单词,找出该单词是否存在于网格中. 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中"相邻"单元格是那些水平相邻或垂直相邻的单元格.同一个单 ...

  7. LeetCode——79. 单词搜索

    给定一个二维网格和一个单词,找出该单词是否存在于网格中. 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中"相邻"单元格是那些水平相邻或垂直相邻的单元格.同一个单元格内的字 ...

  8. leetcode刷题-79单词搜索

    题目 给定一个二维网格和一个单词,找出该单词是否存在于网格中. 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格.同一个单元格内的字母不允许被重复 ...

  9. LeetCode 79. 单词搜索(Word Search)

    题目描述 给定一个二维网格和一个单词,找出该单词是否存在于网格中. 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格.同一个单元格内的字母不允许被 ...

随机推荐

  1. webgl实现发光线框(glow wireframe)效果

    在之前这篇文章, WebGL 单通道wireframe渲染 我们介绍了webgl如何实现单通道wireframe的效果. 本篇文章就是在此技术原理基础之上,来实现发光的wireframe效果. 要实现 ...

  2. SpringCloud系列之API网关(Gateway)服务Zuul

    1.什么是API网关 API网关是所有请求的入口,承载了所有的流量,API Gateway是一个门户一样,也可以说是进入系统的唯一节点.这跟面向对象设计模式中的Facet模式很像.API Gatewa ...

  3. Linux安装python 3

    方法: 1.官网下载地址:http://www.python.org/download/ 2.rz -y 上传到Linux  解压tar -xvzf Python-3.5.1.tgz  进入目录   ...

  4. java简单内存图

    一 内存的分区 二 以数组为例画内存图 代码: class Demo01 { public static void main(String[] args) { //1.数据类型[] 数组名=new 数 ...

  5. [C#] (原创)一步一步教你自定义控件——02,ScrollBar(滚动条)

    一.前言 技术没有先进与落后,只有合适与不合适. 本篇的自定义控件是:滚动条(ScollBar). 我们可以在网上看到很多自定义的滚动条控件,它们大都是使用UserControl去做,即至少使用一个P ...

  6. centos7下安装docker与镜像加速

    1.背景 centos7下安装docker 2.安装 第一步:检查是否为centos7版本 第二步:依赖环境安装 执行如下两个命令: yum -y install gcc yum -y install ...

  7. 深度学习 | sklearn的train_test_split()各函数参数含义解释(超级全)

    在机器学习中,我们通常将原始数据按照比例分割为"测试集"和"训练集",从 sklearn.model_selection 中调用train_test_split ...

  8. python 去除Excel中的重复行数据

    导入pandas import pandas as pd 1.读取excel中的数据: frame = pd.DataFrame(pd.read_csv('excel的绝对路径.csv'', 'She ...

  9. SpringSecurity权限管理系统实战—五、整合SpringSecurity(下)

    系列目录 前言 上篇文章SpringSecurity整合了一半,这次把另一半整完,所以本篇的序号接着上一篇. 七.自定义用户信息 前面我们登录都是用的指定的用户名和密码或者是springsecurit ...

  10. 使用hexo+github搭建博客

    https://blog.csdn.net/qq_36667170/article/details/105789610这一篇已经写得很详细了,下面的内容是我操作的时候遇到的问题及解决方法. 1.下载N ...