leetcode 回溯(三)

排列是整个数组遍历,组合是从该下标开始遍历后续数据,去重:先排序,然后有相同元素,若前面的元素未使用则给元素也不用,否则会产生重复解,可以借助used数组记录该下标对应的元素是否使用过了。

目录

1034. 边框着色

417. 太平洋大西洋水流问题

51. N皇后


1034. 边框着色

https://leetcode-cn.com/problems/coloring-a-border/

给出一个二维整数网格 grid,网格中的每个值表示该位置处的网格块的颜色。只有当两个网格块的颜色相同,而且在四个方向中任意一个方向上相邻时,它们属于同一连通分量。连通分量的边界是指连通分量中的所有与不在分量中的正方形相邻(四个方向上)的所有正方形,或者在网格的边界上(第一行/列或最后一行/列)的所有正方形。给出位于 (r0, c0) 的网格块和颜色 color,使用指定颜色 color 为所给网格块的连通分量的边界进行着色,并返回最终的网格 grid 。

示例 1:输入:grid = [[1,1],[1,2]], r0 = 0, c0 = 0, color = 3,输出:[[3, 3], [3, 2]]
示例 2:输入:grid = [[1,2,2],[2,3,2]], r0 = 0, c0 = 1, color = 3,输出:[[1, 3, 3], [2, 3, 3]]
示例 3:输入:grid = [[1,1,1],[1,1,1],[1,1,1]], r0 = 1, c0 = 1, color = 2,输出:[[2, 2, 2], [2, 1, 2], [2, 2, 2]]
提示:1 <= grid.length <= 50,1 <= grid[0].length <= 50,1 <= grid[i][j] <= 1000,0 <= r0 < grid.length,0 <= c0 < grid[0].length,1 <= color <= 1000

题解

一:注意与733. 图像渲染的区别,733是连通分量重的所有值均替换成新值,所以可以不用used标记,直接修改,修改过了即遍历过了。这边借鉴463. 岛屿的周长的法二,DFS求解。在遇到上下左右边界且值为oldColor时替换成新值。这边我们注意used的赋值,只有访问到且值为oldColor时才标记,733不用标记,是因为值的修改,每个oldColor的值都会修改,就不用额外标记,而这边不是所有的值都会修改(只会修改边界以及和别的颜色的区别处)。借鉴463. 岛屿的周长,对别的颜色分解处修改,所以得放在循环里面。463题无所谓放在哪,因为不需要准确的位置,只需要计数就可。

class Solution(object):
    def colorBorder(self, grid, r0, c0, color):
        """
        :type grid: List[List[int]]
        :type r0: int
        :type c0: int
        :type color: int
        :rtype: List[List[int]]
        """
        def DFS(x, y, oldColor, color):
            if (x < 0 or x >= len(image) or y < 0 or y>= len(image[0])) or used[x][y]:
               return 
            if image[x][y] == oldColor:
                used[x][y] = True
            if ((x == 0 or x == len(image) - 1 
                or y == 0 or y == len(image[0]) - 1) and image[x][y] == oldColor):
                image[x][y] = color

            for p in pos:
                t_x = x + p[0]
                t_y = y + p[1]
                if (t_x < 0 or t_x >= len(image) or t_y < 0 or t_y >= len(image[0])):
                    continue
                if image[t_x][t_y] != oldColor and not used[t_x][t_y]:
                    image[x][y] = color
                    continue
                DFS(t_x, t_y, oldColor, color)

        m, n = len(grid), len(grid[0])
        oldColor = grid[r0][c0]
        image = [[grid[i][j] for j in xrange(n)] for i in xrange(m)]
        if oldColor == color:
            return image

        pos = [[0, 1], [1, 0], [0, -1], [-1, 0]] 
        used = [[False] * n for _ in xrange(m)]
        
        DFS(r0, c0, oldColor, color)

        return image

417. 太平洋大西洋水流问题

https://leetcode-cn.com/problems/pacific-atlantic-water-flow/

给定一个 m x n 的非负整数矩阵来表示一片大陆上各个单元格的高度。“太平洋”处于大陆的左边界和上边界,而“大西洋”处于大陆的右边界和下边界。规定水流只能按照上、下、左、右四个方向流动,且只能从高到低或者在同等高度上流动。请找出那些水流既可以流动到“太平洋”,又能流动到“大西洋”的陆地单元的坐标。

提示:输出坐标的顺序不重要,m 和 n 都小于150
示例:给定下面的 5x5 矩阵:

  太平洋 ~   ~   ~   ~   ~ 
       ~  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  *
          *   *   *   *   * 大西洋

返回:[[0, 4], [1, 3], [1, 4], [2, 2], [3, 0], [3, 1], [4, 0]] (上图中带括号的单元).

题解

一:从边界开始反推,反推人往高处走,每次都走向更高的海拔或者在同海拔间移动。感觉这样编程比水往低处流的正向思考更容易些。

class Solution(object):
    def pacificAtlantic(self, matrix):
        """
        :type matrix: List[List[int]]
        :rtype: List[List[int]]
        """
        def DFS(x, y, visited):
            if (x < 0 or x >= len(matrix) or y < 0 or y >= len(matrix[0])):
                return 
            visited[x][y] = True

            for p in pos:
                t_x = x + p[0]
                t_y = y + p[1]
                if (t_x < 0 or t_x >= len(matrix) or t_y < 0 or t_y >= len(matrix[0])
                   or visited[t_x][t_y] or matrix[x][y] > matrix[t_x][t_y]):
                    continue
                DFS(t_x, t_y, visited)
            
        if not matrix or not matrix[0]:
            return []
        
        # Pacific 大西洋 Atlantic 太平洋
        m, n = len(matrix), len(matrix[0])
        pos = [[0, 1], [1, 0], [0, -1], [-1, 0]]
        
        visited_Pacific = [[False] * n for _ in xrange(m)]
        for j in xrange(n):
            DFS(0, j, visited_Pacific)
        for i in xrange(m):
            DFS(i, 0, visited_Pacific)

        visited_Atlantic = [[False] * n for _ in xrange(m)]
        for j in xrange(n):
            DFS(m - 1, j, visited_Atlantic)
        for i in xrange(m):
            DFS(i, n - 1, visited_Atlantic)

        res = [[i, j] for i in xrange(m) for j in xrange(n) 
               if visited_Pacific[i][j] and visited_Atlantic[i][j]]
        return res

51. N皇后

n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

上图为 8 皇后问题的一种解法。

给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。

示例:输入: 4
输出: [
 [".Q..",  // 解法 1
  "...Q",
  "Q...",
  "..Q."],

 ["..Q.",  // 解法 2
  "Q...",
  "...Q",
  ".Q.."]
]
解释: 4 皇后问题存在两个不同的解法。
提示:皇后,是国际象棋中的棋子,意味着国王的妻子。皇后只做一件事,那就是“吃子”。当她遇见可以吃的棋子时,就迅速冲上去吃掉棋子。当然,她横、竖、斜都可走一到七步,可进可退。(引用自 百度百科 - 皇后 )

题解

一:递归,每次尝试在index行放入一个皇后(一行只能放一个),所以若index行的j列放一个皇后不会发生冲突,则下一次index可加1,即状态会产生改变,若不可以 ,for循环继续找该行中的后续位置(递归状态不改变,只是for 循环中列的位置向后遍历),若该行中均没有可以放置不引起冲突的列,则进行回溯,退回到上一层,遍历上一层的下一个列位置j。row[i]表示i行的皇后放在row[i]列,这个用来记录的。还有col,diag1和diag2列表是为了快速判断(每列,每个对角线位置)是否会有冲突的。

class Solution(object):
    def solveNQueens(self, n):
        """
        :type n: int
        :rtype: List[List[str]]
        """
        def ping():
            tmp = []
            for i in xrange(n):
                tmp.append('.' * row[i] + 'Q' +'.' * (n - 1 - row[i]))
            res.append(tmp)
        
        # DFS,每次尝试排列index行的皇后
        def DFS(index, n):
            if index == n:
                ping()
            for j in xrange(n):
                if not col[j] and not diag1[index + j] and not diag2[index - j + (n - 1)]:
                    row[index] = j
                    col[j] = True
                    diag1[index + j] = True
                    diag2[index - j + (n - 1)] = True
                    DFS(index + 1, n)
                    col[j] = False
                    diag1[index + j] = False
                    diag2[index - j + (n - 1)] = False
        
        # 用来记录,以便快速判断是否有冲突
        col, diag1, diag2 = [False] * n, [False] * (2 * n + 1), [False] * (2 * n + 1)
        # 用来记录
        row = [-1] * n

        res = []
        DFS(0, n)
        return res

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值