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. PHP 实现大文件视频推流

    /** * 视频推流 * 返回视频流 */ function bofang(){ set_time_limit(0); ini_set('max_execution_time', 0);//秒为单位, ...

  2. Anaconda下载安装

    下载地址: 链接:https://pan.baidu.com/s/1fmJkMSL6amJF4KP5JwklOQ 提取码:dsyc 安装完成之后,记得配置系统环境变量:

  3. pytest常用参数汇总

    1.  -s    表示输出调试信息,包括print打印信息 D:\demo>pytest -s ./pytest_1 ===================================== ...

  4. 第三篇:前端基础之JavaScript

    前端基础之JavaScript   JavaScript概述 ECMAScript和JavaScript的关系 1996年11月,JavaScript的创造者--Netscape公司,决定将JavaS ...

  5. apt install protobuf

    protobuf介绍:https://www.cnblogs.com/niuben/p/14212711.html protobuf利用源码编译安装已经看到过很多方法,这里总结下用apt安装的方法. ...

  6. 数据库日志——binlog、redo log、undo log扫盲

    日志是数据库中比较重要的组成部分,很多核心的功能必须依靠日志才能完成. 该篇文章简要介绍了binlog.redo log与undo log,能够在一定程度上拓宽对mysql日志的整体认识. binlo ...

  7. HashSet集合介绍-哈希值

    HashSet集合介绍 java.util.HashSet是set 接口的一个实现类,它所存储的元素是不可重复的,并且元素都是无序的(即存取顺序不一致).java.util.HashSet底层的实现其 ...

  8. DNS 是如何影响你冲浪速度的?

    本文详细介绍了 DNS 相关知识,包括 DNS 工作原理.如何提升域名解析速度.以及 DNS 记录与报文等内容. 1. 域名与域名服务器 在日常上网过程中,出于好记的原因,人们更喜欢在浏览器中输入网站 ...

  9. 【教程搬运】分析并编写suricata规则(内含两个示例)

    suricata规则分析 参考1 参考2 Suricata 签名的结构 在高层次上,Suricata签名由三部分组成: Action:当流量符合规则时采取的行动 Header:一个标题,描述主机.IP ...

  10. 微信公众号签名错误(invalid signature)的问题排查

    之前写好的代码,好多项目一直在用没啥问题,今天做新项目,在调用的时候,wx.config提示签名错误(invalid signature),这搞得相当郁闷,没办法,只能重新一点一点调试. 按照官方的说 ...