代码随想录算法训练营第二十五天|491.递增子序列 46.全排列 47.全排列 II 51.N皇后 37.解数独

491.递增子序列

491. 非递减子序列 - 力扣(LeetCode)

代码随想录

思路:因为这道题不能将数组进行排序,所以不能通过之前的去重方法,而是要使用set,来存放已经用过的数字,不过需要注意的是,uset是每一次调用backstring重新定义的,每一层调用都是一个单独的uset

class Solution(object):
    def findSubsequences(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        result,path=[],[]
        def backstring(start):
            if len(path)>1:
                result.append(path[:])
            uset=set()
            for i in range(start,len(nums)):  
                if (path and path[-1]>nums[i]) or nums[i] in uset:
                    continue
                uset.add(nums[i])
                path.append(nums[i])
                backstring(i+1)
                path.pop()
        backstring(0)
        return result

46.全排列

46. 全排列 - 力扣(LeetCode)

代码随想录

思路:排列问题和组合问题的区别就是排列问题每一次的遍历都需要从头开始,没有start这个变量,所以说需要使用used数组,如果这个下标遍历过了就改为True,并且这个used数组要参与回溯

class Solution(object):
    def permute(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        result,path=[],[]
        used=[False]*len(nums)
        def backstring():
            if len(path)==len(nums):
                result.append(path[:])
                return
            for i in range(len(nums)):
                if used[i]:
                    continue
                used[i]=True
                path.append(nums[i])
                backstring()
                path.pop()
                used[i]=False
        backstring()
        return result

47.全排列 II

47. 全排列 II - 力扣(LeetCode)

代码随想录

思路:和上一题的区别在于需要去重,去重也是和之前差不多,先排序,然后当nums[i]==nums[i-1]并且used[i-1]==0时,也就是和前一个相同并且前一个没有被使用过,注意这个used[i-1]==0,说明是同一层重复而不是同一枝上重复

class Solution(object):
    def permuteUnique(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        result,path=[],[]
        nums.sort()
        used=[False]*len(nums)
        def backstring():
            if len(path)==len(nums):
                result.append(path[:])
                return
            for i in range(len(nums)):
                if (i>0 and nums[i]==nums[i-1] and not used[i-1]) or used[i]:
                    continue
                used[i]=True
                path.append(nums[i])
                backstring()
                path.pop()
                used[i]=False
        backstring()
        return result

51.N皇后 

51. N 皇后 - 力扣(LeetCode)

代码随想录

思路:这道题难点在于怎么想到使用回溯的方法,其实就是按行递归,每一行都最多只会有一个皇后,然后按照列的顺序依次尝试,每一次尝试都要递归到底部。然后还需要完成判断一个皇后是否合法,就是使用列协分别判断,需要注意的是1、不用判断行,因为代码中每一行只可能同时出现一个,而列和斜只需要比较在自己上方的部分就可以

class Solution(object):
    def solveNQueens(self, n):
        """
        :type n: int
        :rtype: List[List[str]]
        """
        result=[]
        chessboard=['.'*n for _ in range(n)]
        def backstring(row):
            if row==n:
                print(chessboard)
                result.append(chessboard[:])
                return
            for col in range(n):
                if isValid(row,col):
                    chessboard[row]=chessboard[row][:col]+'Q'+chessboard[row][col+1:]
                    backstring(row+1)
                    chessboard[row]=chessboard[row][:col]+'.'+chessboard[row][col+1:]
        def isValid(row,col):
            for i in range(row):
                if chessboard[i][col]=='Q':
                    return False
            i,j=row-1,col-1
            while i>=0 and j>=0:
                if chessboard[i][j]=='Q':
                    return False
                i-=1
                j-=1
            i,j=row-1,col+1
            while i>=0 and j<n:
                if chessboard[i][j]=='Q':
                    return False
                i-=1
                j+=1
            return True
        backstring(0)
        return result
            

37.解数独

37. 解数独 - 力扣(LeetCode)

代码随想录

思路:这道题就更加复杂了,递归的思路本质上和上一题差不多,就是每一行按位置找,同时每一个都有可能是1-9的数字,然后再往下枚举列。而在判断是否在区间内的时候,可以用row//3*3来获得那个区间的起始位置。不过这道题实际上没写出来,因为按我的方法好像会超时,需要先计算一遍每一行,每一列,每一区间中已经存放了哪些数字。

class Solution:
    def solveSudoku(self, board: List[List[str]]) -> None:
        """
        Do not return anything, modify board in-place instead.
        """
        row_used = [set() for _ in range(9)]
        col_used = [set() for _ in range(9)]
        box_used = [set() for _ in range(9)]
        for row in range(9):
            for col in range(9):
                num = board[row][col]
                if num == ".":
                    continue
                row_used[row].add(num)
                col_used[col].add(num)
                box_used[(row // 3) * 3 + col // 3].add(num)
        self.backtracking(0, 0, board, row_used, col_used, box_used)

    def backtracking(
        self,
        row: int,
        col: int,
        board: List[List[str]],
        row_used: List[List[int]],
        col_used: List[List[int]],
        box_used: List[List[int]],
    ) -> bool:
        if row == 9:
            return True

        next_row, next_col = (row, col + 1) if col < 8 else (row + 1, 0)
        if board[row][col] != ".":
            return self.backtracking(
                next_row, next_col, board, row_used, col_used, box_used
            )

        for num in map(str, range(1, 10)):
            if (
                num not in row_used[row]
                and num not in col_used[col]
                and num not in box_used[(row // 3) * 3 + col // 3]
            ):
                board[row][col] = num
                row_used[row].add(num)
                col_used[col].add(num)
                box_used[(row // 3) * 3 + col // 3].add(num)
                if self.backtracking(
                    next_row, next_col, board, row_used, col_used, box_used
                ):
                    return True
                board[row][col] = "."
                row_used[row].remove(num)
                col_used[col].remove(num)
                box_used[(row // 3) * 3 + col // 3].remove(num)
        return False

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值