代码随想录算法训练营 Day 22

3 minute read

Published:

Q1. LeetCode 491

去重逻辑与LeetCode 90的区别:不能对原数组排序,因此记录已遇见的元素

class Solution:
    def findSubsequences(self, nums: List[int]) -> List[List[int]]:
        res = []

        def backtracking(start, arr):
            if len(arr) > 1:
                res.append(arr[:])
            
            # 因为题目限制,也可用数组替代
            used = set()
            for i in range(start, len(nums)):
                if (arr and nums[i] < arr[-1]) or nums[i] in used:
                    continue
                
                used.add(nums[i])
                arr.append(nums[i])
                backtracking(i + 1, arr)
                arr.pop()
        
        backtracking(0, [])

        return res

复杂度分析

时间复杂度:O($n \times 2^n$) 空间复杂度:O($n$)

Q2. LeetCode 46

题目要求返回的是所有排列,而排列是有序的 (e.g. $[1,2]$和$[2,1]$两者不同),因此每次都需要从头遍历

class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        res = []

        # used数组表示对应位置的元素是否已被使用
        def backtracking(used, arr):
            if sum(used) == len(nums):
                res.append(arr[:])
                return
            
            for i in range(len(nums)):
                if used[i]:
                    continue
                
                used[i] = 1
                arr.append(nums[i])
                backtracking(used, arr)
                arr.pop()
                used[i] = 0
        
        backtracking([0] * len(nums), [])

        return res

复杂度分析

时间复杂度:O($n!$) 空间复杂度:O($n$)

Q3. LeetCode 47

注意两种去重的逻辑,理解为什么第二种更高效。参考代码随想录

class Solution:
    def permuteUnique(self, nums: List[int]) -> List[List[int]]:
        res = []
        nums.sort()

        # used数组表示对应位置的元素是否已被使用
        def backtracking(used, arr):
            if sum(used) == len(nums):
                res.append(arr[:])
                return
            
            for i in range(len(nums)):
                if (i > 0 and nums[i] == nums[i - 1] and used[i - 1]) or used[i]:
                    continue
                
                used[i] = 1
                arr.append(nums[i])
                backtracking(used, arr)
                arr.pop()
                used[i] = 0
        
        backtracking([0] * len(nums), [])

        return res

class Solution:
    def permuteUnique(self, nums: List[int]) -> List[List[int]]:
        res = []
        nums.sort()

        # used数组表示对应位置的元素是否已被使用
        def backtracking(used, arr):
            if sum(used) == len(nums):
                res.append(arr[:])
                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] = 1
                arr.append(nums[i])
                backtracking(used, arr)
                arr.pop()
                used[i] = 0
        
        backtracking([0] * len(nums), [])

        return res

复杂度分析

时间复杂度:O($n! \times n$) 空间复杂度:O($n$)

Q4. LeetCode 332

class Solution:
    def findItinerary(self, tickets: List[List[str]]) -> List[str]:
        t = defaultdict(list)
        for source, dest in tickets:
            t[source].append(dest)
        
        for city in t:
            t[city].sort()

        res = []

        def backtracking(city):
            while t[city]:
                next_city = t[city].pop(0)
                backtracking(next_city)
            # 当没有下一个城市时,将当前城市放进结果集中
            res.append(city)
        
        backtracking('JFK')

        return res[::-1]

Q5. LeetCode 51

经典的N皇后问题:1. 皇后不能同行;2. 皇后不能同列;3. 皇后不能在一条斜线

class Solution:
    def solveNQueens(self, n: int) -> List[List[str]]:
        res = []
        
        def is_vaid(row, col, board):
            # 判断是否有同一列的皇后
            for i in range(row):
                if board[i][col] == 'Q':
                    return False
            
            # 判断45度角是否有皇后
            i, j = row - 1, col - 1
            while i >= 0 and j >= 0:
                if board[i][j] == 'Q':
                    return False
                i -= 1
                j -= 1
            
            # 判断135度角是否有皇后
            i, j = row - 1, col + 1
            while i >= 0 and j < len(board):
                if board[i][j] == 'Q':
                    return False
                i -= 1
                j += 1
            
            return True
        
        def backtracking(r, board):
            if r == n:
                res.append(board[:])
                return
            
            # 每次都往一行加入一个皇后,保证了皇后不同行
            for c in range(n):
                if is_vaid(r, c, board):
                    board[r] = board[r][:c] + 'Q' + board[r][c + 1:]
                    backtracking(r + 1, board)
                    board[r] = board[r][:c] + '.' + board[r][c + 1:]

        init_board = ['.' * n for _ in range(n)]
        backtracking(0, init_board)

        return res

复杂度分析

时间复杂度:O($n!$) 空间复杂度:O($n$)

Q6. LeetCode 37

二维递归:与N皇后不同,判断条件需要遍历所有行和所有列

class Solution:
    def solveSudoku(self, board: List[List[str]]) -> None:
        """
        Do not return anything, modify board in-place instead.
        """
        def is_valid(r, c, num, b):
            # 判断同一行
            for j in range(9):
                if b[r][j] == str(num):
                    return False
            
            # 判断同一列
            for i in range(9):
                if b[i][c] == str(num):
                    return False

            # 判断所处九方格
            start_r = (r // 3) * 3
            start_c = (c // 3) * 3

            for i in range(3):
                for j in range(3):
                    if b[start_r + i][start_c + j] == str(num):
                        return False

            return True 

        def backtracking(b):
            for i in range(len(b)):
                for j in range(len(b[0])):
                    if b[i][j] != '.':
                        continue
                    for n in range(1, 10):
                        if is_valid(i, j, n, b):
                            b[i][j] = str(n)
                            if backtracking(b):
                                return True
                            b[i][j] = '.'
                    return False
        
            return True

        backtracking(board)

TODO

Q4 - Q6巩固