單詞接龍
給定兩個單詞(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