491.递增子序列
思路:因为这道题不能将数组进行排序,所以不能通过之前的去重方法,而是要使用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.全排列
思路:排列问题和组合问题的区别就是排列问题每一次的遍历都需要从头开始,没有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
思路:和上一题的区别在于需要去重,去重也是和之前差不多,先排序,然后当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皇后
思路:这道题难点在于怎么想到使用回溯的方法,其实就是按行递归,每一行都最多只会有一个皇后,然后按照列的顺序依次尝试,每一次尝试都要递归到底部。然后还需要完成判断一个皇后是否合法,就是使用列协分别判断,需要注意的是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.解数独
思路:这道题就更加复杂了,递归的思路本质上和上一题差不多,就是每一行按位置找,同时每一个都有可能是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

395

被折叠的 条评论
为什么被折叠?



