单词接龙
给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则:
每次转换只能改变一个字母。
转换过程中的中间单词必须是字典中的单词。
说明:
如果不存在这样的转换序列,返回 0。
所有单词具有相同的长度。
所有单词只由小写字母组成。
字典中不存在重复的单词。
你可以假设 beginWord 和 endWord 是非空的,且二者不相同。
示例 1:
输入:
beginWord = “hit”,
endWord = “cog”,
wordList = [“hot”,“dot”,“dog”,“lot”,“log”,“cog”]
输出: 5
解释: 一个最短转换序列是 “hit” -> “hot” -> “dot” -> “dog” -> “cog”,
返回它的长度 5。
示例 2:
输入:
beginWord = “hit”
endWord = “cog”
wordList = [“hot”,“dot”,“dog”,“lot”,“log”]
输出: 0
解释: endWord “cog” 不在字典中,所以无法进行转换。
解法
:
由于是求最短路径,我们很容易想到通过广度优先遍历来解决这个问题。现在我们要解决的问题就变成了如何判断两个单词只有一个字母不同。最简单的办法就是通过26个字母替换:
其他优化方法:https://blog.csdn.net/qq_17550379/article/details/83652490
class Solution(object):
def ladderLength(self, beginWord, endWord, wordList):
"""
:type beginWord: str
:type endWord: str
:type wordList: List[str]
:rtype: int
"""
wordDict = set(wordList)
if endWord not in wordList:
return 0
q = [(beginWord, 1)]
visited = set()
while q:
word, step = q.pop(0)
if word not in visited:
visited.add(word)
if word == endWord:
return step
for i in range(len(word)):
for j in 'abcdefghijklmnopqrstuvwxyz':
tmp = word[:i] + j + word[i+1:]
if tmp not in visited and tmp in wordDict:
q.append((tmp, step + 1))
return 0
岛屿数量
给定一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。
示例 1:
输入:
11110
11010
11000
00000
输出: 1
示例 2:
输入:
11000
11000
00100
00011
输出: 3
解法
标准的回溯问题:遍历整个矩阵,找到为1的就上下左右遍历,并把遍历过的设置为0,因为不会再遍历第二次(省掉visited数组).
回溯其实还可以通过队列的防止保存下来,用迭代解决。
class Solution(object):
def numIslands(self, grid):
"""
:type grid: List[List[str]]
:rtype: int
"""
if not grid:
return 0
res = 0
for i in range(len(grid)):
for j in range(len(grid[0])):
if grid[i][j] == '1':
res += 1
self.dfs(grid, i, j)
return res
def dfs(self, grid, x, y):
grid[x][y] = '0'
if x > 0 and grid[x-1][y] == '1':
self.dfs(grid, x-1, y)
if x < len(grid) - 1 and grid[x+1][y] == '1':
self.dfs(grid, x+1, y)
if y > 0 and grid[x][y-1] == '1':
self.dfs(grid, x, y-1)
if y < len(grid[0]) - 1 and grid[x][y+1] == '1':
self.dfs(grid, x, y+1)
课程表
现在你总共有 n 门课需要选,记为 0 到 n-1。
在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0,1]
给定课程总量以及它们的先决条件,判断是否可能完成所有课程的学习?
示例 1:
输入: 2, [[1,0]]
输出: true
解释: 总共有 2 门课程。学习课程 1 之前,你需要完成课程 0。所以这是可能的。
示例 2:
输入: 2, [[1,0],[0,1]]
输出: false
解释: 总共有 2 门课程。学习课程 1 之前,你需要先完成课程 0;并且学习课程 0 之前,你还应先完成课程 1。这是不可能的。
说明:
输入的先决条件是由边缘列表表示的图形,而不是邻接矩阵。详情请参见图的表示法。
你可以假定输入的先决条件中没有重复的边。
提示:
这个问题相当于查找一个循环是否存在于有向图中。如果存在循环,则不存在拓扑排序,因此不可能选取所有课程进行学习。
通过 DFS 进行拓扑排序 - 一个关于Coursera的精彩视频教程(21分钟),介绍拓扑排序的基本概念。
拓扑排序也可以通过 BFS 完成。
解法
拓扑排序:在图论中,拓扑排序(Topological Sorting)是一个有向无环图(DAG, Directed Acyclic Graph)的所有顶点的线性序列。且该序列必须满足下面两个条件:
每个顶点出现且只出现一次。
若存在一条从顶点 A 到顶点 B 的路径,那么在序列中顶点 A 出现在顶点 B 的前面。
有向无环图(DAG)才有拓扑排序,非DAG图没有拓扑排序一说。
所以可以使用拓扑排序的方法,可以拓扑排序的结点数等于课程数,则表示可以完成拓扑排序,即可以完成课程。
另外一种方法:https://www.jianshu.com/p/4565fa200a62
class Solution(object):
def canFinish(self, numCourses, prerequisites):
"""
:type numCourses: int
:type prerequisites: List[List[int]]
:rtype: bool
"""
if not prerequisites:
return True
in_degree = [0 for i in range(numCourses)]
adj = [set() for i in range(numCourses)]
for x, y in prerequisites:
in_degree[x] += 1
adj[y].add(x)
q = []
for x in range(numCourses):
if in_degree[x] == 0:
q.append(x)
res = 0
while q:
tmp = q.pop(0)
res += 1
for x in adj[tmp]:
in_degree[x] -= 1
if in_degree[x] == 0:
q.append(x)
return res == numCourses