leetcode题解: 搜索

BFS

3. 最短单词路径

  1. Word Ladder (Medium)

Input:

beginWord = "hit",

endWord = "cog",

wordList = ["hot","dot","dog","lot","log","cog"]

Output: 5

Explanation: As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog",

return its length 5.

Input:

beginWord = "hit"

endWord = "cog"

wordList = ["hot","dot","dog","lot","log"]

Output: 0

Explanation: The endWord "cog" is not in wordList, therefore no possible transformation.

题目描述:找出一条从 beginWord 到 endWord 的最短路径,每次移动规定为改变一个字符,并且改变之后的字符串必须在 wordList 中。

基础解法(词表长度太长的时候会超时)

class Solution:
def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int:
wordList.append(beginWord)
n = len(wordList)
start = n-1
end = 0
while end < n and wordList[end] != endWord:
end += 1
if end == n:
return 0
graphic = self.buildGraphic(wordList)
return self.getShortestPath(graphic, start, end) def buildGraphic(self, wordList):
n = len(wordList)
graphic = [[]]*n
for i in range(n):
cur = []
for j in range(n):
if self.isConnect(wordList[i], wordList[j]):
cur.append(j)
graphic[i] = cur
return graphic def isConnect(self, s1, s2):
diffCnt = 0
for i in range(len(s1)):
if diffCnt > 1:
return False
if s1[i] != s2[i]:
diffCnt += 1
return diffCnt == 1 def getShortestPath(self, graphic, start, end):
queue = collections.deque()
queue.append(start)
marked = [False]*len(graphic)
path = 1
while len(queue) > 0:
size = len(queue)
path+=1
for j in range(size-1, -1, -1):
cur = queue.popleft()
for idx in graphic[cur]:
if idx == end:
return path
if marked[idx]:
continue
marked[idx] = True
queue.append(idx)
return 0

优化解法

class Solution:
def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int:
def addWord(word: str):
if word not in word2id:
nonlocal nodeNum
word2id[word] = nodeNum
nodeNum += 1
def addEdge(word: str):
addWord(word)
id1 = word2id[word]
chars = list(word)
for i in range(len(chars)):
tmp = chars[i]
chars[i] = "*"
newWord = "".join(chars)
addWord(newWord)
id2 = word2id[newWord]
edges[id2].append(id1)
edges[id1].append(id2)
chars[i] = tmp word2id = {}
edges = collections.defaultdict(list)
nodeNum = 0 for word in wordList:
addEdge(word)
addEdge(beginWord)
if endWord not in wordList:
return 0
beginId, endId = word2id[beginWord], word2id[endWord] queue = collections.deque()
queue.append(beginId)
dis = [float('inf')]*nodeNum
dis[beginId] = 0 while queue:
x = queue.popleft()
print(x)
if x == endId:
return dis[x]//2+1
for i in edges[x]:
if dis[i] == float('inf'):
dis[i] = dis[x] +1
queue.append(i)
return 0

DFS

广度优先搜索一层一层遍历,每一层得到的所有新节点,要用队列存储起来以备下一层遍历的时候再遍历。

而深度优先搜索在得到一个新节点时立即对新节点进行遍历:从节点 0 出发开始遍历,得到到新节点 6 时,立马对新节点 6 进行遍历,得到新节点 4;如此反复以这种方式遍历新节点,直到没有新节点了,此时返回。返回到根节点 0 的情况是,继续对根节点 0 进行遍历,得到新节点 2,然后继续以上步骤。

从一个节点出发,使用 DFS 对一个图进行遍历时,能够遍历到的节点都是从初始节点可达的,DFS 常用来求解这种 可达性 问题。

在程序实现 DFS 时需要考虑以下问题:

  • 栈:用栈来保存当前节点信息,当遍历新节点返回时能够继续遍历当前节点。可以使用递归栈。
  • 标记:和 BFS 一样同样需要对已经遍历过的节点进行标记。

1. 最大连通面积

695. Max Area of Island (Medium)

class Solution:
def dfs(self, grid, cur_i, cur_j) -> int:
if cur_i < 0 or cur_j < 0 or cur_i == len(grid) or cur_j == len(grid[0]) or grid[cur_i][cur_j] != 1:
return 0
grid[cur_i][cur_j] = 0
ans = 1
for di, dj in [[0, 1], [0, -1], [1, 0], [-1, 0]]:
next_i, next_j = cur_i + di, cur_j + dj
ans += self.dfs(grid, next_i, next_j)
return ans def maxAreaOfIsland(self, grid: List[List[int]]) -> int:
ans = 0
for i, l in enumerate(grid):
for j, n in enumerate(l):
ans = max(self.dfs(grid, i, j), ans)
return ans

2. 矩阵中的连通分量

  1. Number of Islands (Medium)
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
res = 0
for i in range(0, len(grid)):
for j in range(0, len(grid[0])):
if grid[i][j] == '1':
res +=1
self.infect(grid, i, j)
return res def infect(self, grid, i, j):
if i< 0 or i >= len(grid) or j < 0 or j >= len(grid[0]) or grid[i][j] != '1':
return
grid[i][j] = '2'
self.infect(grid, i-1, j)
self.infect(grid, i+1, j)
self.infect(grid, i, j-1)
self.infect(grid, i, j+1)

Backtracking

在矩阵中寻找字符串

  1. Word Search (Medium)
class Solution:
def exist(self, board: List[List[str]], word: str) -> bool:
directions = [(0, 1), (0, -1), (1, 0), (-1, 0)] def check(i: int, j: int, k: int, word_len: int) -> bool:
if board[i][j] != word[k]:
return False
if k == word_len:
return True visited.add((i, j))
result = False
for di, dj in directions:
newi, newj = i + di, j + dj
if 0 <= newi < h and 0 <= newj <w:
if (newi, newj) not in visited:
if check(newi, newj, k + 1, word_len):
result = True
break visited.remove((i, j))
return result h, w = len(board), len(board[0])
n = len(word)-1
visited = set()
for i in range(h):
for j in range(w):
if check(i, j, 0, n):
return True return False

5. 全排列

  1. Permutations (Medium)
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
res = []
path = []
self.dfs(nums, path, res)
return res def dfs(self, nums, path, res):
if len(path) == len(nums):
res.append(path[:]) for num in nums:
if num in path:
continue
path.append(num)
self.dfs(nums, path, res)
path.remove(num)

6. 含有相同元素全排列

  1. Permutations II (Medium)
class Solution:
def permuteUnique(self, nums: List[int]) -> List[List[int]]:
visited = [0 for i in nums]
nums.sort()
res = []
path = []
self.dfs(nums, path, res, visited)
return res def dfs(self, nums, path, res, visited):
if len(path) == len(nums):
res.append(path) for i in range(len(nums)):
if visited[i] == 1:
continue
if i > 0 and nums[i - 1] == nums[i] and visited[i - 1] == 0:
continue
# path.append(nums[i])
visited[i] = 1
self.dfs(nums, path+[nums[i]], res, visited)
visited[i] = 0
# path.pop() # def permuteUnique(self, nums: List[int]) -> List[List[int]]:
# res = []
# path = []
# self.dfs(nums, path, res, 0, len(nums))
# return res # def dfs(self, nums, path, res, start, k):
# if len(path) == k:
# if path not in res:
# res.append(path[:]) # for i in range(start, k):
# # if nums[i] == nums[start]:
# # continue
# path.append(nums[i])
# nums[i], nums[start] = nums[start], nums[i]
# self.dfs(nums, path, res, start + 1, k)
# nums[i], nums[start] = nums[start], nums[i]
# path.pop()

7. 组合

  1. 组合

    题目描述:给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。

你可以按 任何顺序 返回答案。

class Solution:
def combine(self, n: int, k: int) -> List[List[int]]:
if k<=0 or k > n:
return []
res = []
path = []
self.dfs(n, k, 1, path, res)
return res def dfs(self, n, k, start, path, res):
if len(path) == k:
res.append(path[:])
return
for i in range(start, n+1):
path.append(i)
self.dfs(n, k, i+1, path, res)
path.pop()

8.组合求和

39. 组合总和

给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。

candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。

对于给定的输入,保证和为 target 的不同组合数少于 150 个。

class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
res = []
path = []
candidates.sort()
self.dfs(candidates, path, res, target)
return res def dfs(self, candidates, path, res, target):
if target < 0:
return
if target == 0:
# res.append(path[:])
cur = path[:]
cur.sort()
if cur not in res:
res.append(cur)
for i in range(len(candidates)):
cur = candidates[i]
if cur > target:
return
if i > 0 and cur == candidates[i-1]:
continue
path.append(cur)
self.dfs(candidates, path, res, target-cur)
path.pop()

9.含有相同元素的组合求和

40. 组合总和 II

class Solution:
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
res = []
path = []
candidates.sort()
self.dfs(target, path, res, candidates, 0)
if sum(candidates) < target:
return []
return res def dfs(self, target, path, res, candidates, start):
if target < 0:
return
if target == 0:
cur = path[:]
cur.sort()
if cur not in res:
res.append(cur) for i in range(start, len(candidates)):
if candidates[i] > target:
return
if i > start and candidates[i] == candidates[i-1]:
continue
path.append(candidates[i])
self.dfs(target-candidates[i], path, res, candidates, i+1)
path.pop()

最短路径(todo)



MAX= float('inf')

matrix = [
[0,10,MAX,4,MAX,MAX],
[10,0,8,2,6,MAX],
[MAX,8,10,15,1,5],
[4,2,15,0,6,MAX],
[MAX,6,1,6,0,12],
[MAX,MAX,5,MAX,12,0]
] def dijkstra(matrix, start_node): #矩阵一维数组的长度,即节点的个数
matrix_length = len(matrix) #访问过的节点数组
used_node = [False] * matrix_length #最短路径距离数组
distance = [MAX] * matrix_length #初始化,将起始节点的最短路径修改成0
distance[start_node] = 0 #将访问节点中未访问的个数作为循环值,其实也可以用个点长度代替。
while used_node.count(False):
min_value = float('inf')
min_value_index = 999 #在最短路径节点中找到最小值,已经访问过的不在参与循环。
#得到最小值下标,每循环一次肯定有一个最小值
for index in range(matrix_length):
if not used_node[index] and distance[index] < min_value:
min_value = distance[index]
min_value_index = index #将访问节点数组对应的值修改成True,标志其已经访问过了
used_node[min_value_index] = True #更新distance数组。
#以B点为例:distance[x] 起始点达到B点的距离,
#distance[min_value_index] + matrix[min_value_index][index] 是起始点经过某点达到B点的距离,比较两个值,取较小的那个。
for index in range(matrix_length):
distance[index] = min(distance[index], distance[min_value_index] + matrix[min_value_index][index]) return distance start_node = int(input('请输入起始节点:'))
result = dijkstra(matrix,start_node)
print('起始节点到其他点距离:%s' % result)

搜索(todo)的更多相关文章

  1. 基于TODO的开发方法

    之前买了一本书,叫<架构探险-从零开始写Java Web框架 >(不推荐购买-),一本标题党书籍!但是我很推崇作者写代码的方式,就是基于TODO的方式进行开发! 个人认为以基于TODO的方 ...

  2. mysql 全文搜索 FULLTEXT

    到 3.23.23 时,MySQL 开始支持全文索引和搜索.全文索引在 MySQL 中是一个 FULLTEXT 类型索引.FULLTEXT 索引用于 MyISAM 表,可以在 CREATE TABLE ...

  3. [Odoo12基础教程]之第一篇-创建Todo应用

    声明: 本教程基于 Ruter 老师的 [Odoo基础教程系列] ,Ruter老师教程的链接地址为:Odoo基础教程系列   . 至于为什么已经有了Ruter老师的教程,还要自己再搬移一份呢?是基于一 ...

  4. 印象笔记作为todo(GTD相关)的一个尝试

    印象笔记作为todo(GTD相关)的一个尝试 上来说结果: 失败 原则上的原因: 印象笔记作为一个比较重的笔记, 重点也不在于这一点, 虽然是可以新建清单之类的. 还是比较小巧的好一些. 最后使用的软 ...

  5. intellij系列编辑器个性化注释说明(定义个人风格的todo)

    有时候我们需要用于自己个性化的注释,不为装逼,只为能够快速找到自己的注释,自己的代码,不迷路... 废话少说,孩儿们看过来: 1.打开你的编辑器,打开setting,搜索TODO: 设置完点击保存去试 ...

  6. 小小TODO标识,你用对了吗?

    前言 有时,您需要标记部分代码以供将来参考,比如: 优化,改进,可能的更改,要讨论的问题等. 通常我们会在代码中加入如下的标记表示待办: //TODO 我将要在这里做 xxx 你这样做,别人也会这样做 ...

  7. [VSCode] Todo Tree VSCode插件 待办事项树

    Todo Tree 一款待办事项插件 我们写程序的时候,难免会遇到一些情况需要标记或者搁置,在写代码的时候会用一些特殊的注释来表示不同的内容,使我们可以快速的定位我们注释的位置. 主要有以下几种: T ...

  8. [已开源/文章教程]独立开发 一个社交 APP 的源码/架构分享 (已上架)

    0x00 背景 真不是和被推荐了2天的博客园一位大神较真,从他那篇文章的索引式文章内容也学习到了很多东西,看评论区那么多对社交APP源码有兴趣的,正巧我上周把我的一个社交APP开源了,包括androi ...

  9. mysql 函数编程大全(持续更新)

    insert ignore insert ignore表示,如果中已经存在相同的记录,则忽略当前新数据 如果您使用一个例如“SET col_name = col_name + 1”的赋值,则对位于右侧 ...

  10. Chromium Embedded Framework 中文文档(简介)

    转自:http://www.cnblogs.com/think/archive/2011/10/06/CEF-Introduce.html 简介 Chromium Embedded Framework ...

随机推荐

  1. 侦察工具——Httrack

    前言 web渗透学习笔记,实验环境为Metasploitable靶机上的DVWA.此随笔介绍Web渗透侦察工具Httrack Httrack 简介 Httrack能够克隆拷贝目标网站上的所有可访问.可 ...

  2. 常用 Git 命令行操作

    本文记录了一些常用 Git 命令行操作的具体使用方式 git clone git clone REPOSITORY_URL 拉取仓库,并使用仓库名作为本地文件名 git clone REPOSITOR ...

  3. Auto-Job任务调度框架

    Auto-Job 任务调度框架 一.背景 生活中,业务上我们会碰到很多有关作业调度的场景,如每周五十二点发放优惠券.或者每天凌晨进行缓存预热.亦或每月定期从第三方系统抽数等等,Spring和java目 ...

  4. test20230109考试总结-2023寒搜索专题

    前言 2023 年的第一篇考试总结-- 赛时得分情况: A B C D E F G \(\texttt{Total}\) \(\texttt{Rank}\) \(40\) \(80\) \(0\) \ ...

  5. 使用 Link Cut Tree 维护最小生成树

    简介 本文将简单介绍如何使用 Link Cut Tree 维护动态图最小生成树. 思路 最小生成树的性质:一个基环树的最小生成树,为将环上边权最大的边删除后所组成的树. Proof:如果删除环上的其他 ...

  6. scratch图形化编程教程

    1. scratch软件 市面上类似于scratch这种图形化编程的软件非常多,各个品牌的都有,而且每个品牌之后的风格.界面布局也是不同的,所以我会简单的列举一些对应软件. scratch3.0 优点 ...

  7. 02安装一个最小化的Hadoop

    安装一个最小化的Hadoop 为了学习HDFS和之后的MapReduce,我们需要安装一个Hadoop. Hadoop一共有3种运行模式 独立模式:不启动守护进程,所有程序运行在一个JVM进程中.独立 ...

  8. Python对字典进行赋值操作时报错:“Cannot assign to function call”解决方案

    今天编程时对字典进行赋值操作时报错"Cannot assign to function call": 翻译一下就是无法分配函数调用的空间. 我很纳闷,因为前面都可以正常调用dict ...

  9. 1.31 wlx 魔怔 9 解法交互题小结

    参考题解地址 1. 从树上任意一个节点开始,跳到其随机一个后代,跳到叶子的期望次数为 \(H_{siz_u}=\ln(siz_u)\). 证明: 首先考虑一条链的情况.设在第 \(i\) 个点期望次数 ...

  10. 淘宝首页数据采集之js采集

    搜索页面采集,数据在控制台哦!!! 搜索页面采集,数据在控制台哦!!! 搜索页面采集,数据在控制台哦!!! 既然能打到控制台,当然也能传到系统!!! 既然能打到控制台,当然也能传到系统!!! 既然能打 ...