数据结构与算法分类练习--DFS BFS

深度优先遍历:对每一个可能的分支路径深入到不能再深入为止,不全部保留结点,占用空间少;有回溯操作(即有入栈、出栈操作),运行速度慢。

广度优先遍历:又叫层次遍历,从上往下对每一层依次访问,在每一层中,从左往右(也可以从右往左)访问结点,访问完一层就进入下一层,保留全部结点,占用空间大; 常用优先队列,无回溯操作,运行速度快。

Number of Islands 小岛数量

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

这道题的本质是求矩阵中连续区域的个数,我们使用DFS来解。找到一个为“1”的位置后总和加1,并递归的将其四周为“1”的位置置“0”。然后寻找下一个为“1”的位置。

class Solution(object):    
    def numIslands(self, grid):
        """
        :type grid: List[List[str]]
        :rtype: int
        """
        if not grid:
            return 0
        m = len(grid[0])
        n = len(grid)
        def sink (x, y):
            if 0 <= x < n and 0 <= y < m and grid[x][y] == '1':
                grid[x][y] = '0'
                map(sink, [x-1, x+1, x, x], [y, y, y-1, y+1])
                return 1
            return 0
        return sum(sink(x, y) for x in xrange(n) for y in xrange(m))

Matchsticks to Square 火柴棍能否组成正方形

Your input will be several matchsticks the girl has, represented with their stick length. Your output will either be true or false, to represent whether you could make one square using all the matchsticks the little match girl has.You should not break any stick, but you can link them up, and each matchstick must be used exactly one time.

Example: Input: [3,3,3,3,4] Output: false

我们可以使用位运算来表示数组中每个位置的状态。用used_subsets记录总和为边长的子数组V,用valid_half_subsets来记录两个V加起来和为周长的一半的子数组W。遍历所有子数组,如果当前子数组的和正好为边长,然后判断是否能和其他已知的V位置不重叠,如果有则进行组合存入valid_half_subsets,剩余的数值如果也存在valid_half_subsets中则返回Ture。

class Solution(object):
    def makesquare(self, nums):
        """
        :type nums: List[int]
        :rtype: bool
        """
        total_len = sum(nums)
        if total_len % 4:
            return False

        side_len = total_len / 4
        fullset = (1 << len(nums)) - 1

        used_subsets = []
        valid_half_subsets = [0] * (1 << len(nums))

        for subset in xrange(fullset+1):
            # 遍历所有子数组
            subset_total_len = 0
            for i in xrange(len(nums)): 
                if subset & (1 << i):
                    subset_total_len += nums[i]

            if subset_total_len == side_len:
                for used_subset in used_subsets:
                    if (used_subset & subset) == 0:
                        valid_half_subset = used_subset | subset
                        valid_half_subsets[valid_half_subset] = True
                        if valid_half_subsets[fullset ^ valid_half_subset]:
                            return True
                used_subsets.append(subset)
        return False

Increasing Subsequences 递增子序列

Given an integer array, your task is to find all the different possible increasing subsequences of the given array, and the length of an increasing subsequence should be at least 2 .The given array may contain duplicates, and two equal integers should also be considered as a special case of increasing sequence.

和普通的生成子序列有两点不同:第一是需要去重,可以通过set()来辅助实现,最后再变回列表;第二是递增,可以在生成子序列的时候进行对比,看当前的数值是否不小于要扩充的子序列的最后一个数值。

Example: Input: [4, 6, 7, 7] Output: [[4, 6], [4, 7], [4, 6, 7], [4, 6, 7, 7], [6, 7], [6, 7, 7], [7,7], [4,7,7]]

class Solution(object):
    def findSubsequences(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        tmp = set()
        for n in nums:
            for y in list(tmp):
                if n >= y[-1]:
                    tmp.add(y + (n,))
            tmp.add((n,))
        return list(e for e in tmp if len(e) > 1)

附tmp的部分运行状态:

Word Ladder 词语阶梯

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:

  1. Only one letter can be changed at a time.
  2. Each transformed word must exist in the word list. Note that beginWord is not a transformed word.
  3. All words have the same length.

Example:

Input: beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"] Output: 5 "hit" -> "hot" -> "dot" -> "dog" -> "cog"

从beginword开始,对每个字符进行替换,如果替换后的单词在wordlist里则将其加入next集合中,供下一轮遍历;如果替换后的单词是backward则之接返回length。

class Solution(object):
    def ladderLength(self, beginWord, endWord, wordList):
        """
        :type beginWord: str
        :type endWord: str
        :type wordList: List[str]
        :rtype: int
        """
        wordList = set(wordList)
        forward, backward, length = {beginWord}, {endWord}, 2
        dic = set(string.ascii_lowercase)
        if endWord not in wordList:return 0
        while forward and backward:
            next = set()
            for word in forward:
                for i in range(len(word)):
                    first, second = word[:i], word[i + 1:]
                    for item in dic:
                        candidate = first + item + second
                        if candidate in backward:
                            return length
                        if candidate in wordList:
                            wordList.discard(candidate)
                            next.add(candidate)
            forward = next
            length += 1
        return 0

Pacific Atlantic Water Flow 太平洋大西洋水流

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.

Given the following 5x5 matrix:

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

从四条边开始逆流遍历,最后取左上两边能到达的地方和右下两边能达到的地方的交集即可。

class Solution(object):
    def pacificAtlantic(self, matrix):
        """
        :type matrix: List[List[int]]
        :rtype: List[List[int]]
        """
        if not matrix: return []
        m,n = len(matrix), len(matrix[0])
        
        pacific = set([(i,0) for i in range(m)] + [(0,j) for j in range(n)])
        atlantic = set([(i,n-1) for i in range(m)] + [(m-1,j) for j in range(n)])
        
        def bfs(s):
            q=list(s)
            while q:
                i,j = q.pop(0)
                for di,dj in (0,1),(1,0),(0,-1),(-1,0):
                    ii,jj = i+di,j+dj
                    if 0<=ii<m and 0<=jj<n and matrix[ii][jj]>=matrix[i][j] and (ii,jj) not in s:
                        s.add((ii,jj))
                        q.append((ii,jj))
            return s
        
        return list(bfs(pacific) & bfs(atlantic))

Trapping Rain Water II 收集雨水

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.

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.

利用优先队列,将四周的高度/坐标存入,从最低点开始遍历四周,模拟海平面上升。如果发现未访问过的点,进行标记不再访问,如果高度低于当前高度则将存水量加入curr_res并以此点为中心继续向四周遍历。

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, pq = len(heightMap), len(heightMap[0]), []
        for i, j in zip([0]*n + range(1, m-1)*2 + [m-1]*n, range(n)+[0]*(m-2)+[n-1]*(m-2)+range(n)):
            heapq.heappush(pq, (heightMap[i][j], i, j))
            heightMap[i][j] = -1
        #do dfs
        res = 0
        def dfs(i, j, curr_height, curr_res):
            for next_i, next_j in ((i+1, j), (i-1, j), (i, j+1), (i, j-1)):
                if 0<=next_i<len(heightMap) and 0<=next_j<len(heightMap[0]) and heightMap[next_i][next_j] >= 0:
                    new_height = heightMap[next_i][next_j]
                    heightMap[next_i][next_j] = -1
                    if new_height < curr_height:
                        #we can secure how much water?
                        curr_res += curr_height-new_height
                        #continue to expand
                        curr_res = dfs(next_i, next_j, curr_height, curr_res)  
                    else:
                        heapq.heappush(pq, (new_height, next_i, next_j))
                
            return curr_res
        
        #for all the boundary points...
        while pq:
            curr_height, curr_i, curr_j = heapq.heappop(pq)
            res = dfs(curr_i, curr_j, curr_height, res)
        return res

猜你喜欢

转载自blog.csdn.net/ZJL0105/article/details/81416825