LeetCode 79,这道走迷宫问题为什么不能用宽搜呢?
本文始发于个人公众号:TechFlow,原创不易,求个关注
今天是LeetCode专题第48篇文章,我们一起来看看LeetCode当中的第79题,搜索单词(Word Search)。
这一题官方给的难度是Medium,通过率是34.5%,点赞3488,反对170。单从这份数据上来看,这题的质量很高,并且难度比之前的题目稍稍大一些。我个人觉得通过率是比官方给的题目难得更有参考意义的指标,10%到20%可以认为是较难的题,30%左右是偏难的题。50%是偏易题,所以如果看到某题标着Hard,但是通过率有50%,要么说明题目很水,要么说明数据很水,总有一点很水。
题意
废话不多说,我们来看题意:
这题的题面挺有意思,给定一个二维的字符型数组,以及一个字符串,要求我们来判断能否在二维数组当中找到一条路径,使得这条路径上的字符连成的字符串和给定的字符串相等?
样例
board =
[
['A','B','C','E'],
['S','F','C','S'],
['A','D','E','E']
]
Given word = "ABCCED", return true.
Given word = "SEE", return true.
Given word = "ABCB", return false.
比如第一个字符串ABCCED,我们可以在数组当中找到这样一条路径:
题解
不知道大家看到题面和这个样例有什么样的感觉,如果你刷过许多题,经常思考的话,我想应该不难发现,这道题的本质其实和走迷宫问题是一样的。
我们拿到的这个二维的字符型数组就是一个迷宫, 我们是要在这个迷宫当中找一条“出路”。不过我们的目的不是找到终点,而是找到一条符合题意的路径。在走迷宫问题当中,迷宫中不是每一个点都可以走的,同样在当前问题当中,也不是每一个点都符合字符串的要求的。这两个问题虽然题面看起来大相径庭,但是核心的本质是一样的。
我们来回忆一下,走迷宫问题应该怎么解决?
这个答案应该已经非常确定了,当然是搜索算法。我们需要搜索解可能存在的空间去寻找存在的解,也就是说我们面临的是一个解是否存在的问题,要么找到解,要么遍历完所有的可能性发现解不存在。确定了是搜索算法之后,剩下的就简单了,我们只有两个选项,深度优先或者是广度优先。
理论上来说,一般判断解的存在性问题,我们使用广度优先搜索更多,因为一般来说它可以更快地找到解。但是本题当中有一个小问题是,广度优先搜索需要在队列当中存储中间状态,需要记录地图上行走过的信息,每有一个状态就需要存储一份地图信息,这会带来比较大的内存开销,同样存储的过程也会带来计算开销,在这道题当中,这是不可以接受的。拷贝状态带来的空间消耗还是小事,关键是拷贝带来的时间开销,就足够让这题超时了。所以我们别无选择,只能深度优先。
明确了算法之后,只剩下了最后一个问题,在这个走迷宫问题当中,我们怎么找到迷宫的入口呢?因为题目当中并没有规定我们起始点的位置,这也不难解决,我们遍历二维的字符数组,和字符串开头相匹配的位置都可以作为迷宫的入口。
最后,我们来看代码,并没有什么技术含量,只是简单的回溯法而已。
class Solution:
def exist(self, board: List[List[str]], word: str) -> bool:
fx = [[0, 1], [0, -1], [1, 0], [-1, 0]]
def dfs(x, y, l):
if l == len(word):
return True
for i in range(4):
nx = x + fx[i][0]
ny = y + fx[i][1]
# 出界或者是走过的时候,跳过
if nx < 0 or nx == n or ny < 0 or ny == m or visited[nx][ny]:
continue
if board[nx][ny] == word[l]:
visited[nx][ny] = 1
if dfs(nx, ny, l+1):
return True
visited[nx][ny] = 0
return False
n = len(board)
if n == 0:
return False
m = len(board[0])
if m == 0:
return False
visited = [[0 for i in range(m)] for j in range(n)]
for i in range(n):
for j in range(m):
# 找到合法的起点
if board[i][j] == word[0]:
visited = [[0 for _ in range(m)] for _ in range(n)]
visited[i][j] = 1
if dfs(i, j, 1):
return True
return False
总结
如果能够想通回溯法,并且对于回溯法的实现足够熟悉,那么这题的难度是不大的。实际上至今为止,我们一路刷来,已经做了好几道回溯法的问题了,我想对你们来说,回溯法的问题应该已经小菜一碟了。
相比于回溯法来说,我觉得更重要的是我们能够通过分析想清楚,为什么广度优先搜索不行,底层核心的本质原因是什么。这个思考的过程往往比最后的结论来得重要。
如果喜欢本文,可以的话,请点个关注,给我一点鼓励,也方便获取更多文章。
本文使用 mdnice 排版
LeetCode 79,这道走迷宫问题为什么不能用宽搜呢?的更多相关文章
- 老鼠走迷宫II
转自:http://blog.csdn.net/holymaple/article/details/8636234 由于迷宫的设计,老鼠走迷宫的入口至出口路径可能不止一条,如何求出所有的路径呢? 解法 ...
- 老鼠走迷宫I
转自:http://blog.csdn.net/holymaple/article/details/8582517 说明:老鼠走迷宫是递回求解的基本提醒,我们在二维阵列中使用2来表示迷宫墙壁,使用1来 ...
- C语言动态走迷宫
曾经用C语言做过的动态走迷宫程序,先分享代码如下: 代码如下: //头文件 #include<stdio.h> #include<windows.h>//Sleep(500)函 ...
- sdut 2449走迷宫【最简单的dfs应用】
走迷宫 Time Limit: 1000ms Memory limit: 65536K 有疑问?点这里^_ 题目描述 一个由n * m 个格子组成的迷宫,起点是(1, 1), 终点是(n, m) ...
- 洛谷P1238 走迷宫
洛谷1238 走迷宫 题目描述 有一个m*n格的迷宫(表示有m行.n列),其中有可走的也有不可走的,如果用1表示可以走,0表示不可以走,文件读入这m*n个数据和起始点.结束点(起始点和结束点都是用两个 ...
- BZOJ 2707: [SDOI2012]走迷宫( tarjan + 高斯消元 )
数据范围太大不能直接高斯消元, tarjan缩点然后按拓扑逆序对每个强连通分量高斯消元就可以了. E(u) = 1 + Σ E(v) / degree(u) 对拍时发现网上2个程序的INF判断和我不一 ...
- NYOJ306 走迷宫(dfs+二分搜索)
题目描写叙述 http://acm.nyist.net/JudgeOnline/problem.php?pid=306 Dr.Kong设计的机器人卡多非常爱玩.它经常偷偷跑出实验室,在某个游乐场玩之不 ...
- Problem A: 走迷宫问题
Problem A: 走迷宫问题Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 9 Solved: 3[Submit][Status][Web Board] ...
- BZOJ 2707: [SDOI2012]走迷宫 [高斯消元 scc缩点]
2707: [SDOI2012]走迷宫 题意:求s走到t期望步数,\(n \le 10^4\),保证\(|SCC| \le 100\) 求scc缩点,每个scc高斯消元,scc之间直接DP 注意每次清 ...
随机推荐
- Java中的集合(十一) 实现Map接口的TreeMap
Java中的集合(十一) 实现Map接口的TreeMap 一.TreeMap简介(基于JDK1.8) TreeMap是基于红黑树数据结构,是一个key-value的有序集合,该映射根据其键的自然顺序进 ...
- neo4j-jdbc driver
https://github.com/neo4j-contrib/neo4j-jdbc/releases/tag/3.3.1
- css box-shadow(text-shadow) 阴影学习备忘
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Cypress系列(6)- Cypress 的重试机制
如果想从头学起Cypress,可以看下面的系列文章哦 https://www.cnblogs.com/poloyy/category/1768839.html 前言 重试(Retry-ability) ...
- SpringBoot返回html页面
一般Controller返回数据或页面,今天谈一下返回页面的场景. 一.不使用template 1. controller中定义对应的访问路由及返回的页面(使用Controller,不要使用RestC ...
- Java实现 蓝桥杯 算法训练 求平方和
试题 算法训练 求平方和 问题描述 请用函数重载实现整型和浮点习型的两个数的平方和计算 输入格式 测试数据的输入一定会满足的格式. 2 2(2行2列,第1行整型,第2行浮点型) 输出格式 要求用户的输 ...
- Java实现 LeetCode 680 验证回文字符串 Ⅱ(暴力)
680. 验证回文字符串 Ⅱ 给定一个非空字符串 s,最多删除一个字符.判断是否能成为回文字符串. 示例 1: 输入: "aba" 输出: True 示例 2: 输入: " ...
- Java实现 LeetCode 355 设计推特
355. 设计推特 设计一个简化版的推特(Twitter),可以让用户实现发送推文,关注/取消关注其他用户,能够看见关注人(包括自己)的最近十条推文.你的设计需要支持以下的几个功能: postTwee ...
- Java实现 蓝桥杯VIP 算法训练 ALGO-16进制转换
算法训练 进制转换 时间限制:1.0s 内存限制:256.0MB 问题描述 我们可以用这样的方式来表示一个十进制数: 将每个阿拉伯数字乘以一个以该数字所处位置的(值减1)为指数,以10为底数的幂之和的 ...
- java类加载器是什么?
类加载器是有了解吗? 解析:底层原理的考察,其中涉及到类加载器的概念,功能以及一些底层的实现. 答:顾名思义,类加载器(class loader)用来加载 Java 类到 Java 虚拟机中.一般来说 ...