Python數據結構之寬度優先搜索

目錄

  1. 島嶼數量 (LeetCode 200)
  2. 詞語階梯(LeetCode 127)
  3. 詞語階梯2 (LeetCode 126)
  4. 01矩陣 (LeetCode 542)
  5. 太平洋與大西洋的水流 (LeetCode 417)
  6. 收集雨水2 (LeetCode 407)

1. 島嶼數量 (LeetCode 200 Number of Islands)

1.1題目

Given a 2d grid map of ‘1’s (land) and ‘0’s (water), count the number of islands. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.

Example 1:

11110
11010
11000
00000

Answer: 1

Example 2:

11000
11000
00100
00011

Answer: 3

1.2思路

bfs,使用bfs可以將與1相鄰的所有1全部標記爲True,如果出現還沒有被標記的1,則iland數量+1

1.3代碼

class Solution(object):
    def numIslands(self, grid):
        """
        :type grid: List[List[str]]
        :rtype: int
        """
        if not grid:
            return 0
        m = len(grid)
        n = len(grid[0])
        self.visited = [[False for i in range(n)] for j in range(m)]
        ans = 0
        for x in range(m):
            for y in range(n):
                if grid[x][y] == '1' and not self.visited[x][y]:
                    ans += 1
                    self.bfs(grid, x, y, m, n)
        return ans


    def bfs(self, grid, x, y, m, n):
        d = zip([1,0,-1,0],[0,1,0,-1])
        queue = [(x, y)]
        self.visited[x][y] = True
        while queue:
            x, y = queue.pop(0)
            for dx, dy in d:
                nx = x + dx
                ny = y + dy
                if nx >= 0 and nx < m and ny >= 0 and ny < n and grid[nx][ny] == '1' and not self.visited[nx][ny]:
                    self.visited[nx][ny] = True
                    queue.append((nx, ny))

2. 詞語階梯(LeetCode 127 Word Ladder)

2.1題目

Given two words (beginWord and endWord), and a dictionary’s word list, find the length of shortest transformation sequence from beginWord to endWord, such that:

Only one letter can be changed at a time.
Each transformed word must exist in the word list. Note that beginWord is not a transformed word.
For example,

Given:
beginWord = “hit”
endWord = “cog”
wordList = [“hot”,”dot”,”dog”,”lot”,”log”,”cog”]
As one shortest transformation is “hit” -> “hot” -> “dot” -> “dog” -> “cog”,
return its length 5.

Note:
Return 0 if there is no such transformation sequence.
All words have the same length.
All words contain only lowercase alphabetic characters.
You may assume no duplicates in the word list.
You may assume beginWord and endWord are non-empty and are not the same.

2.2思路

遍歷每個單詞,逐一將每個單詞中的每個單詞的各個位置上的字母用’_’代替,並作爲鍵,完整的單詞作爲值,逐一添加。這樣的話值列表中的單詞就是鍵中的鄰接單詞。使用bfs從起始單詞開始,遍歷其鄰接單詞,如果出現結束單詞,就結束,否則將單詞添加到隊列中。

2.3代碼

class Solution(object):
    def ladderLength(self, beginWord, endWord, wordList):
        """
        :type beginWord: str
        :type endWord: str
        :type wordList: List[str]
        :rtype: int
        """
        def word_to_dict(wordlist):
            d = {}
            for word in wordlist:
                for i in range(len(word)):
                    s = word[:i] +'_'+ word[i+1:]
                    d[s] = d.get(s, []) + [word]
            return d
        def bfs(beginword, endword, d):
            queue = [(beginword, 1)]
            visit = set()
            while queue:
                word, step = queue.pop(0)                
                if word not in visit:
                    visit.add(word)
                    if word == endword:
                        return step
                    for i in range(len(word)):
                        s = word[:i] +'_'+ word[i+1:]
                        nei_words = d.get(s, [])
                        for nei in nei_words:
                            if nei not in visit:
                                queue.append((nei, step + 1))
            return 0 
        d = word_to_dict(wordList)
        return bfs(beginWord, endWord, d)

3. 詞語階梯2 (LeetCode 126Word Ladder II)

3.1題目

Given two words (beginWord and endWord), and a dictionary’s word list, find all shortest transformation sequence(s) from beginWord to endWord, such that:

Only one letter can be changed at a time
Each transformed word must exist in the word list. Note that beginWord is not a transformed word.
For example,

Given:
beginWord = “hit”
endWord = “cog”
wordList = [“hot”,”dot”,”dog”,”lot”,”log”,”cog”]
Return

  [
    ["hit","hot","dot","dog","cog"],
    ["hit","hot","lot","log","cog"]
  ]

Note:
Return an empty list if there is no such transformation sequence.
All words have the same length.
All words contain only lowercase alphabetic characters.
You may assume no duplicates in the word list.
You may assume beginWord and endWord are non-empty and are not the same.

3.2思路

將起始單詞設爲起始層單詞集合,遍歷每一層的每個單詞,用’abcdefghijklmnopqrstuvwxyz’中的一個字母代替原始單詞中的各個位置的字母,生成新的單詞,判斷新的單詞是否在給定的單詞列表中,且該單詞在上一層未使用過,則將該單詞加入下一層的列表單詞結合中,使用字典進行存儲:形式爲{子單詞:父單詞}。循環直到endword在父集合中或者該層單詞列表爲空。最後按照字典中的順序從最後一個單詞開始拼接,得到答案。

3.3代碼

class Solution(object):
    def findLadders(self, beginWord, endWord, wordList):
        """
        :type beginWord: str
        :type endWord: str
        :type wordList: List[str]
        :rtype: List[List[str]]
        """
        wordSet = set([])
        for word in wordList:
            wordSet.add(word)

        level = set([beginWord])

        parents = collections.defaultdict(set)

        while level and endWord not in parents:
            next_level = collections.defaultdict(set)
            for word in level:
                for i in range(len(beginWord)):
                    p1 = word[:i]
                    p2 = word[i+1:]
                    for j in 'abcdefghijklmnopqrstuvwxyz':
                        # accelerate 
                        if word[i] != j:
                            childWord = p1 + j + p2
                            if childWord in wordSet and childWord not in parents:
                                next_level[childWord].add(word)
            level = next_level
            parents.update(next_level)

        res = [[endWord]]
        while res and res[0][0] !=beginWord:
            res = [[p]+r for r in res for p in parents[r[0]]]

        return res

4. 01矩陣 (LeetCode 542 01 Matrix)

4.1題目

Given a matrix consists of 0 and 1, find the distance of the nearest 0 for each cell.

The distance between two adjacent cells is 1.
Example 1:

Input:  
0 0 0
0 1 0
0 0 0
Output:
0 0 0
0 1 0
0 0 0

Example 2:

Input:
0 0 0
0 1 0
1 1 1
Output:
0 0 0
0 1 0
1 2 1

4.2思路

0的位置對應的答案一定爲0,故只需討論距離1最近的0的位置即可
使用隊列
初始時,將matrix中所有1元素的位置加入隊列。
循環,直到隊列中的元素爲空
step += 1
遍歷隊列中的元素,記當前元素爲p,座標爲(x,y)
若p的上下左右元素包含0,則p的距離設爲step,從隊列中移除p(使用兩個新的數組,一個表示移除的元素列表,一個表示剩下的元素列表),將上一步中移除的元素對應的matrix中的值設爲0。

4.3代碼

class Solution(object):
    def updateMatrix(self, matrix):
        """
        :type matrix: List[List[int]]
        :rtype: List[List[int]]
        """
        h, w = len(matrix), len(matrix[0])
        ans = [[0 for i in range(w)] for j in range(h)]
        queue = [(x,y) for x in range(h) for y in range(w)  if matrix[x][y]]
        step = 0
        while queue:
            step += 1
            nqueue, mqueue = [], []
            for x, y in queue:
                zero = 0
                for dx, dy in zip((1,0,-1,0),(0,1,0, -1)):
                    nx, ny = x +dx, y + dy
                    if 0 <= nx < h and 0 <= ny < w and matrix[nx][ny] == 0:
                        zero += 1
                if zero:
                    ans[x][y] = step

                    mqueue.append((x,y))
                else:
                    nqueue.append((x,y))  
            for x, y in mqueue:
                matrix[x][y] = 0
            queue = nqueue
        return ans

5. 太平洋與大西洋的水流 (LeetCode 417 Pacific Atlantic Water Flow)

5.1題目

Given an m x n matrix of non-negative integers representing the height of each unit cell in a continent, the “Pacific ocean” touches the left and top edges of the matrix and the “Atlantic ocean” touches the right and bottom edges.

Water can only flow in four directions (up, down, left, or right) from a cell to another one with height equal or lower.

Find the list of grid coordinates where water can flow to both the Pacific and Atlantic ocean.

Note:
The order of returned grid coordinates does not matter.
Both m and n are less than 150.
Example:

Given the following 5x5 matrix:

  Pacific ~   ~   ~   ~   ~ 
       ~  1   2   2   3  (5) *
       ~  3   2   3  (4) (4) *
       ~  2   4  (5)  3   1  *
       ~ (6) (7)  1   4   5  *
       ~ (5)  1   1   2   4  *
          *   *   *   *   * Atlantic

Return:

[[0, 4], [1, 3], [1, 4], [2, 2], [3, 0], [3, 1], [4, 0]] (positions with parentheses in above matrix).

5.2思路

使用queue+bfs
初始化,左邊、上邊的點->{pacific},右邊、上邊的點->{Atlantic}
使用queue實現bfs
對pacific和atlantic中的每個點,先進先出,遍歷其上下左右的點,如果其高度大於等於當前點,則將其加入隊列和集合中。
最後求解{pacific}和{Atlantic}的交集即爲所有可以流入太平洋和大西洋的點集。

5.3代碼

class Solution(object):
    def pacificAtlantic(self, matrix):
        """
        :type matrix: List[List[int]]
        :rtype: List[List[int]]
        """
        m = len(matrix)
        if m == 0:
            return []
        n = len(matrix[0])
        topedge = [(0, y) for y in range(n)]
        leftedge = [(x, 0) for x in range(1,m)]
        rightedge = [(x, n-1) for x in range(m)]
        bottomedge = [(m-1, y) for y in range(n)]
        pacific = set(topedge + leftedge)
        atlantic = set(rightedge + bottomedge)
        def bfs(vset):
            dz = zip((1,0,-1,0),(0,1,0,-1))
            queue = list(vset)
            while queue:
                hx, hy = queue.pop(0)
                for dx, dy in dz:
                    nx, ny = hx + dx, hy + dy
                    if 0 <= nx < m and 0 <= ny < n:
                        if matrix[nx][ny] >= matrix[hx][hy]:
                            if (nx,ny) not in vset:
                                queue.append((nx, ny))
                                vset.add((nx,ny))
        bfs(pacific)
        bfs(atlantic)
        ans = pacific & atlantic
        return map(list,ans)

6. 收集雨水2 (LeetCode 407 Trapping Rain WaterII)

6.1題目

Given an m x n matrix of positive integers representing the height of each unit cell in a 2D elevation map, compute the volume of water it is able to trap after raining.

Note:
Both m and n are less than 110. The height of each unit cell is greater than 0 and is less than 20,000.

Example:

Given the following 3x6 height map:
[
  [1,4,3,1,3,2],
  [3,2,1,3,2,4],
  [2,3,3,2,3,1]
]

Return 4.

6.2思路

bfs
記矩形的高度、寬度分別爲m,n,令二維數組peakMap[i][j]= ,表示矩形區域最多可以達到的水面高度,將矩形的四條邊中的各點座標加入隊列q,並將各點對應的高度賦值給peakMap相同座標;每次從q中彈出隊頭元素x,y,遍歷其上下左右四個方向的點(nx,ny),嘗試用max(peakMap[x][y], heightMap[nx][ny]) 更新 peakMap[nx][ny] 的當前值(取兩者中的較小值)

6.3代碼

class Solution(object):
    def trapRainWater(self, heightMap):
        """
        :type heightMap: List[List[int]]
        :rtype: int
        """

        if len(heightMap) < 3 or len(heightMap[0]) < 3: return 0
        m, n = len(heightMap), len(heightMap[0])
        peakMap = [[0x7fffffff for i in range(n)] for i in range(m)]
        q = []
        for i in range(m):
            for j in range(n):
                if i in (0, m-1) or j in (0, n-1):
                    peakMap[i][j] = heightMap[i][j]
                    q.append((i, j))
        while q:
            x, y = q.pop(0)
            for dx, dy in zip([-1,0,1,0],[0,-1,0,1]):
                nx, ny = x+dx, y+dy
                if nx >= 0 and nx < m and ny >= 0 and ny < n:
                    limit = max(peakMap[x][y], heightMap[nx][ny])
                    if peakMap[nx][ny] > limit:
                        peakMap[nx][ny] = limit
                        q.append((nx, ny))
        return sum(peakMap[x][y] - heightMap[x][y] for x in range(m) for y in range(n))
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章