算法刷题打卡026 |回溯6-终篇

首先跟随代码随想录进行了最近回溯刷题的总结,加深理解和记忆(我真的好像记性不是很好...)。回溯和递归相伴相生,在树的遍历中其实也经常涉及回溯,一开始我也很怵递归和回溯,不太习惯递归的思路,刷题下来已经形成了一些肌肉记忆,理解回溯的树形结构也很有帮助。记住,只能用回溯的题目,本质上也是在暴力枚举,只是一般的for循环没法实现,时间复杂度没有优化,最多能针对特定问题可以做一些剪枝。回溯解决的问题类型包括组合排列切割子集,以及今天才刷的棋盘问题(是第一次刷题时还不敢碰的题),做题其实最需要的是透过现象看本质,不然即便知道有什么解题方法,不会用也是白费!好了,还是多刷题吧。

LeetCode 332.重新安排行程

题目链接:332. 重新安排行程 - 力扣(Leetcode)

“本题其实是一道深度优先搜索的题目,但是我完全使用回溯法的思路来讲解这道题题目,算是给大家拓展一下思维方式,其实深搜和回溯也是分不开的,毕竟最终都是用递归。”看完讲解,第一次刷这道题真的一脸懵:还能这样?所以当下也就是照葫芦画瓢:

class Solution:
    def findItinerary(self, tickets: List[List[str]]) -> List[str]:
        tickets_dict = collections.defaultdict(list)
        for fr, to in tickets:
            tickets_dict[fr].append(to)
        # 对每个机场的到达机场列表排序,以保证最终输出是字典序最小的结果
        for air in tickets_dict:
            tickets_dict[air].sort()
        
        path = ['JFK']
        def backtracking(start):
            if len(path) == len(tickets) + 1:
                return True
            for _ in tickets_dict[start]:
                end = tickets_dict[start].pop(0)
                path.append(end)
                if backtracking(end):
                    return True
                path.pop()
                tickets_dict[start].append(end) 
        
        backtracking('JFK')
        return path

LeetCode 51.N皇后

题目链接:51. N 皇后 - 力扣(Leetcode)

N皇后的题目倒是容易理解,尝试不看讲解自己做题,卡在去重上了,result数组陷入了奇怪的循环(也不算循环,就是没有及时跳出怪圈),而且发现返回结果还有点问题,忘记用字符串数组的join:

class Solution:

    def markAttack(self, n, grid, x, y):
        # 将当前x,y上的皇后的可攻击位置标记为False
        changed = [[False] * n for _ in range(n)]
        def changAndMark(j, k):
            if grid[j][k] == True:
                grid[j][k] = False
                changed[j][k] = True
        # 行 列
        for i in range(n):
            changAndMark(x, i)
            changAndMark(i, y)
        # 对角线
        step = 1
        for i in range(y-1, -1, -1):
            if  x + step < n:
                changAndMark(x + step, i) 
            if x -  step >= 0:
                changAndMark(x - step, i)
            step += 1
        step = 1
        for i in range(y+1, n):
            if  x + step < n:
                changAndMark(x + step, i) 
            if x -  step >= 0:
                changAndMark(x - step, i)
            step += 1
        return changed

    def reverseMark(self, idx, grid, n):
        for i in range(n):
            for j in range(n):
                if idx[i][j]:
                    grid[i][j] = True

    def solveNQueens(self, n: int) -> List[List[str]]:
        grid, path = [[True] * n for _ in range(n)], [['.'] * n for _ in range(n)]
        result = []

        def backtracking(num_queen):
            # if sum(grid) == 0 and num_queen < n:
            #     return
            if num_queen == n:
                res = []
                for p in path:
                    res.append(p[:])
                result.append(res)
                return 
            for i in range(n):
                for j in range(n):
                    if not grid[i][j]:
                        continue  # 该位置已经不能放皇后
                    path[i][j] = 'Q'
                    idx = self.markAttack(n, grid, i, j)
                    backtracking(num_queen + 1)
                    path[i][j] = '.'
                    self.reverseMark(idx, grid, n)  # 回溯把grid中修改了的位置还原
        
        backtracking(0)
        return result

 讲解的逻辑清晰多了,也不用这么多判断条件诶:

class Solution:
    def solveNQueens(self, n: int) -> List[List[str]]:
        if not n: return []
        board = [['.'] * n for _ in range(n)]
        res = []
        def isVaild(board,row, col):
            #判断同一列是否冲突
            for i in range(len(board)):
                if board[i][col] == 'Q':
                    return False
            # 判断左上角是否冲突
            i = row -1
            j = col -1
            while i>=0 and j>=0:
                if board[i][j] == 'Q':
                    return False
                i -= 1
                j -= 1
            # 判断右上角是否冲突
            i = row - 1
            j = col + 1
            while i>=0 and j < len(board):
                if board[i][j] == 'Q':
                    return False
                i -= 1
                j += 1
            return True

        def backtracking(board, row, n):
            # 如果走到最后一行,说明已经找到一个解
            if row == n:
                temp_res = []
                for temp in board:
                    temp_str = "".join(temp)
                    temp_res.append(temp_str)
                res.append(temp_res)
            for col in range(n):
                if not isVaild(board, row, col):
                    continue
                board[row][col] = 'Q'
                backtracking(board, row+1, n)
                board[row][col] = '.'
        backtracking(board, 0, n)
        return res

今天在N皇后上花了不少时间,LeetCode 37.解数独这道题之后有时间再补上!

你可能感兴趣的:(刷题,算法,leetcode)