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. 分享一个自己在用的.net 中mysql事务控制类(支持多条sql,参数化,自定义判断条件,错误点返回等)

    1)首先看下事务控制器. using MySql.Data.MySqlClient; using System; using System.Collections.Generic; using Sys ...

  2. LeetCode-03 无重复字符的最长子串(Longest Substring Without Repeating Characters)

    题目描述 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度. 示例 示例  1: 输入: "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 &qu ...

  3. Nodejs报错记录

    ◉ digital envelope routines::unsupported D:\workspace\vuedemo> npm run dev ... error:0308010C:dig ...

  4. AspNetCore管道

    title: Asp.Net Core底层源码剖析(一)中间件/管道 categories: 后端 tags: - .NET 当我们像下面这样添加一个管道时发生了什么? app.Use(async ( ...

  5. 网络流棋盘模型 | P3355 骑士共存问题 P4304 [TJOI2013]攻击装置

    题面(骑士共存问题) 在一个 \(n \times n\) 个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示.棋盘上某些方格设置了障碍,骑士不得进入. 对于给定的 \(n \times n ...

  6. 题解 CF1579G Minimal Coverage

    CF1579G Minimal Coverage dp好题! link to the problem 解法 首先需要观察到:如果最长线段的长度为\(maxL\),那么答案不可能超过\(2maxL\) ...

  7. Cocos Creator 打包原生 Android 包该如何选择 NDK 版本?

    大家好,我是晓衡! 记得前段时间,在一些群里看到有小伙伴说 Cocos Creator 打包 Android 原生 APK 有问题:一种是构建失败,一种是运行起来报错. 晓衡也是有好长一段时间,没有碰 ...

  8. file类创建删除功能的方法-file类遍历(文件夹)目录功能

    file类创建删除功能的方法 public boolean createNewFile():当且仅当具有该名称的文件尚不存在时,创建一个新的空文件.public boolean delete(︰删除由 ...

  9. Argus 与其他(非Oracle B2B)EDI 工具的集成

    Argus 是Oracle 的产品,它自然推荐使用Oracle 自己的EDI 系统,这个系统就是Oracle B2B.但是Argus 留有与其他EDI 工具的集成空间,即即使不使用Oracle B2B ...

  10. Java CompletableFuture 异步超时实现探索

    作者:京东科技 张天赐 前言 JDK 8 是一次重大的版本升级,新增了非常多的特性,其中之一便是 CompletableFuture.自此从 JDK 层面真正意义上的支持了基于事件的异步编程范式,弥补 ...