标签:开始 数字 入行 cti sel jin app 有一个 填充
给定一个没有重复数字的序列, 返回其所有可能的全排列. 示例:
输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
from typing import List
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
def dfs(path, visited, res):
if len(path) == len(nums):
res.append(path[:])
return None
for i in range(len(nums)):
if visited[i]:
continue
path.append(nums[i])
visited[i] = True
dfs(path, visited, res)
path.pop()
visited[i] = False
if len(nums) == 0:
return []
res = []
path = []
visited = [False for _ in range(len(nums))]
dfs(path, visited, res)
return res
ans = Solution()
nums = [1, 2, 3]
print(ans.permute(nums))
注意在此 res.append(path[:])
不能写作 res.append(path)
, 因为变量 path
是引用传递 (本质上是变量内存地址的值传递), 在深度优先搜索完成之后就回到了根节点, 此时列表 path
为空. 解决的办法是应用列表的切片做一次浅拷贝.
给定一个可包含重复数字的序列 nums, 按任意顺序返回所有不重复的全排列. 示例:
输入: nums = [1,1,2]
输出:
[[1,1,2],
[1,2,1],
[2,1,1]]
class Solution:
def permuteUnique(self, nums: List[int]) -> List[List[int]]:
def dfs(path, visited, res):
if len(path) == len(nums):
res.append(path[:])
return None
for i in range(len(nums)):
if visited[i]:
continue
if i > 0 and nums[i] == nums[i - 1] and not visited[i - 1]:
continue
path.append(nums[i])
visited[i] = True
dfs(path, visited, res)
path.pop()
visited[i] = False
if len(nums) == 0:
return []
nums.sort()
res = []
path = []
visited = [False for _ in range(len(nums))]
dfs(path, visited, res)
return res
给定一个无重复元素的数组 candidates 和一个目标数 target, 找出 candidates 中所有可以使数字和为 target 的组合. candidates 中的数字可以无限制重复被选取.
输入: candidates = [2,3,6,7], target = 7,
所求解集为:
[
[7],
[2,2,3]
]
from typing import List
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
def dfs(candidates, target, begin, res, path):
if target == 0:
res.append(path[:])
return None
for i in range(begin, len(candidates)):
if target - candidates[i] < 0:
break
path.append(candidates[i])
dfs(candidates, target - candidates[i], i, res, path)
path.pop()
if len(candidates) == 0:
return []
res = []
path = []
begin = 0
candidates.sort() # 剪枝, 如果没有排序, 则将 break 换为 continue
dfs(candidates, target, begin, res, path)
return res
给定一个数组 candidates 和一个目标数 target, 找出 candidates 中所有可以使数字和为 target 的组合. candidates 中的每个数字在每个组合中只能使用一次.
输入: candidates = [10,1,2,7,6,1,5], target = 8,
所求解集为:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]
from typing import List
class Solution:
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
def dfs(candidates, target, path, res, begin):
if target == 0:
res.append(path[:])
return None
for i in range(begin, len(candidates)):
if target - candidates[i] < 0:
break
if i != begin and candidates[i] == candidates[i - 1]:
continue
path.append(candidates[i])
dfs(candidates, target - candidates[i], path, res, i + 1)
path.pop()
if len(candidates) == 0:
return []
res = []
path = []
begin = 0
candidates.sort()
dfs(candidates, target, path, res, begin)
return res
给定两个整数 n 和 k, 返回 1 ... n 中所有可能的 k 个数的组合. 示例:
输入: n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
class Solution:
def combine(self, n: int, k: int) -> List[List[int]]:
def dfs(n, k, res, path, begin):
if len(path) == k:
res.append(path[:])
return None # 到达叶子节点
for i in range(begin, n + 1):
path.append(i)
dfs(n, k, res, path, i + 1)
path.pop()
if k == 0:
return []
res = []
path = []
dfs(n, k, res, path, 1)
return res
给你一个整数数组 nums, 数组中的元素互不相同. 返回该数组所有可能的子集 (幂集). 解集不能包含重复的子集. 你可以按任意顺序返回解集. 示例:
输入: nums = [1,2,3]
输出: [[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
def dfs(nums, res, path, begin):
res.append(path[:])
for i in range(begin, len(nums)):
path.append(nums[i])
dfs(nums, res, path, i + 1)
path.pop()
if len(nums) == 0:
return []
res = []
path = []
begin = 0
dfs(nums, res, path, 0)
return res
给定一个可能包含重复元素的整数数组 nums, 返回该数组所有可能的子集(幂集). 解集不能包含重复的子集. 示例:
输入: [1,2,2]
输出:
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]
class Solution:
def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
def dfs(nums, res, path, begin):
res.append(path[:])
for i in range(begin, len(nums)):
if i != begin and nums[i] == nums[i - 1]:
continue
path.append(nums[i])
dfs(nums, res, path, i + 1)
path.pop()
if len(nums) == 0:
return []
res = []
path = []
begin = 0
nums.sort()
dfs(nums, res, path, begin)
return res
n 皇后问题研究的是如何将 n 个皇后放置在 n*n 的棋盘上, 并且使皇后彼此之间不能相互攻击, 皇后彼此不能相互攻击, 也就是说: 任何两个皇后都不能处于同一条横行, 纵行或斜线上. 给你一个整数 n, 返回所有不同的 n 皇后问题的解决方案. 每一种解法包含一个不同的 n 皇后问题的棋子放置方案, 该方案中 ‘Q‘ 和 ‘.‘ 分别代表了皇后和空位.
输入:n = 4
输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
class Solution:
def solveNQueens(self, n: int) -> List[List[str]]:
def dfs(n, vertical, diagonal1, diagonal2, begin):
if len(path) == n:
res.append(path[:])
return None
for i in range(begin, n):
for j in range(n):
if vertical[j] or diagonal1[i + j] or diagonal2[i - j]:
continue
vertical[j] = True
diagonal1[i + j] = True
diagonal2[i - j] = True
temp = [‘.‘ for _ in range(n)]
temp[j] = ‘Q‘
path.append(‘‘.join(temp))
dfs(n, vertical, diagonal1, diagonal2, i + 1)
path.pop()
vertical[j] = False
diagonal1[i + j] = False
diagonal2[i - j] = False
return res
if n == 0:
return []
res = []
path = []
vertical = [False for _ in range(n)]
diagonal1 = [False for _ in range(2 * n + 1)]
diagonal2 = [False for _ in range(2 * n + 1)]
dfs(n, vertical, diagonal1, diagonal2, 0)
return res
给你一个整数 n, 返回 n 皇后问题不同的解决方案的数量. 示例:
输入: n = 4
输出: 2
class Solution:
def totalNQueens(self, n: int) -> int:
def dfs(n, vertical, diagonal1, diagonal2, begin):
if len(vertical) == n:
return 1
count = 0
for i in range(begin, n):
for j in range(n):
if j in vertical or i + j in diagonal1 or i - j in diagonal2:
continue
vertical.add(j)
diagonal1.add(i + j)
diagonal2.add(i - j)
count += dfs(n, vertical, diagonal1, diagonal2, i + 1)
vertical.remove(j)
diagonal1.remove(i + j)
diagonal2.remove(i - j)
return count
if n == 0:
return 0
vertical = set()
diagonal1 = set()
diagonal2 = set()
return dfs(n, vertical, diagonal1, diagonal2, 0)
board =
[
[‘A‘,‘B‘,‘C‘,‘E‘],
[‘S‘,‘F‘,‘C‘,‘S‘],
[‘A‘,‘D‘,‘E‘,‘E‘]
]
给定 word = "ABCCED", 返回 true
给定 word = "SEE", 返回 true
给定 word = "ABCB", 返回 false
class Solution:
def exist(self, board: List[List[str]], word: str) -> bool:
directions = [(0, 1), (0, -1), (1, 0), (-1, 0)]
def dfs(i, j, k):
if board[i][j] != word[k]:
return False
if k == len(word) - 1:
return True
board[i][j] = ‘‘
# visited = set(), visited.add((i, j))
for di, dj in directions:
inew, jnew = i + di, j + dj
if 0 <= inew < len(board) and 0 <= jnew < len(board[0]):
if board[inew][jnew] != ‘‘:
if dfs(inew, jnew, k + 1):
return True
board[i][j] = word[k]
# visited.remove((i, j))
return False
for i in range(len(board)):
for j in range(len(board[0])):
if dfs(i, j, 0):
return True
return False
LeetCode.剑指 Offer 13. 机器人的运动范围
地上有一个 m 行 n 列的方格, 从坐标 [0, 0] 到坐标 [m-1, n-1] . 一个机器人从坐标 [0, 0] 的格子开始移动, 它每次可以向左、右、上、下移动一格(不能移动到方格外), 也不能进入行坐标和列坐标的数位之和大于k的格子. 例如, 当k为18时, 机器人能够进入方格 [35, 37] , 因为3+5+3+7=18. 但它不能进入方格 [35, 38], 因为3+5+3+8=19. 请问该机器人能够到达多少个格子?
版本1 深度优先搜索
class Solution:
def movingCount(self, m: int, n: int, k: int) -> int:
def digitsum(x):
s = 0
while x != 0:
s += x % 10
x = x // 10
return s
def dfs(i, j):
nonlocal count # 代替 self.count = 0
count += 1
visited.add((i, j))
for di, dj in directions:
inew, jnew = i + di, j + dj
if 0 <= inew < m and 0 <= jnew < n:
if digitsum(inew) + digitsum(jnew) <= k:
if (inew, jnew) not in visited:
dfs(inew, jnew)
directions = [(0, 1), (0, -1), (1, 0), (-1, 0)]
visited = set()
count = 0
dfs(0, 0)
return count
版本2 可以直接用 len(visited)
代替 count
, 并且机器人只可能向右和下走.
class Solution:
def movingCount(self, m: int, n: int, k: int) -> int:
def digitsum(x):
s = 0
while x != 0:
s += x % 10
x = x // 10
return s
def dfs(i, j, visited):
visited.add((i, j))
if i < m - 1 and (i + 1, j) not in visited:
if digitsum(i + 1) + digitsum(j) <= k:
dfs(i + 1, j, visited)
if j < n - 1 and (i, j + 1) not in visited:
if digitsum(i) + digitsum(j + 1) <= k:
dfs(i, j + 1, visited)
visited = set()
dfs(0, 0, visited)
return len(visited)
版本3 递推
class Solution:
def movingCount(self, m: int, n: int, k: int) -> int:
def digitsum(x):
s = 0
while x > 0:
s += x % 10
x = x // 10
return s
count = 0
visited = set()
visited.add((0, 0))
for i in range(m):
for j in range(n):
if (i == 0 and j == 0) or digitsum(i) + digitsum(j) > k:
continue
if i - 1 >= 0 and (i - 1, j) in visited:
visited.add((i, j))
if j - 1 >= 0 and (i, j - 1) in visited:
visited.add((i, j))
return len(visited)
版本4 广度优先搜索 (使用队列)
class Solution:
def movingCount(self, m: int, n: int, k: int) -> int:
def digitsum(x):
s = 0
while x > 0:
s += x % 10
x = x // 10
return s
queue = deque()
queue.append((0, 0))
visited = set()
while queue:
i, j = queue.pop()
if i >= m or j >= n or digitsum(i) + digitsum(j) > k or (i, j) in visited:
continue
visited.add((i, j))
queue.append((i + 1, j))
queue.append((i, j + 1))
return len(visited)
给你一个 m x n 的矩阵 board, 由若干字符 ‘X‘ 和 ‘O‘ 组成, 找到所有被 ‘X‘ 围绕的区域, 并将这些区域里所有的 ‘O‘ 用 ‘X‘ 填充. 被围绕的区间不会存在于边界上, 换句话说, 任何边界上的 ‘O‘ 都不会被填充为 ‘X‘. 任何不在边界上, 或不与边界上的 ‘O‘ 相连的 ‘O‘ 最终都会被填充为 ‘X‘. 如果两个元素在水平或垂直方向相邻, 则称它们是“相连”的. 示例:
输入: board = [["X","X","X","X"],
["X","O","O","X"],
["X","X","O","X"],
["X","O","X","X"]]
输出: [["X","X","X","X"],
["X","X","X","X"],
["X","X","X","X"],
["X","O","X","X"]]
class Solution:
def solve(self, board: List[List[str]]) -> None:
"""
Do not return anything, modify board in-place instead.
"""
def dfs(board, i, j):
if i < 0 or i >= len(board) or j < 0 or j >= len(board[0]) or board[i][j] != ‘O‘:
return None
board[i][j] = ‘Y‘
directions = [(0, 1), (0, -1), (1, 0), (-1, 0)]
for di, dj in directions:
inew, jnew = i + di, j + dj
dfs(board, inew, jnew)
for i in range(len(board)):
dfs(board, i, 0)
dfs(board, i, len(board[0]) - 1)
for j in range(1, len(board[0]) - 1):
dfs(board, 0, j)
dfs(board, len(board) - 1, j)
for i in range(len(board)):
for j in range(len(board[0])):
if board[i][j] == ‘O‘:
board[i][j] = ‘X‘
if board[i][j] == ‘Y‘:
board[i][j] = ‘O‘
return None
给你一个由 ‘1‘ (陆地) 和 ‘0‘ (水) 组成的的二维网格, 请你计算网格中岛屿的数量. 岛屿总是被水包围, 并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成. 此外, 你可以假设该网格的四条边均被水包围. 示例:
输入: grid = [
["1","1","0","0","0"],
["1","1","0","0","0"],
["0","0","1","0","0"],
["0","0","0","1","1"]
]
输出: 3
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
def dfs(grid, i, j):
if i < 0 or i >= len(grid) or j < 0 or j >= len(grid[0]) or grid[i][j] != ‘1‘:
return None
grid[i][j] = ‘2‘
directions = [(0, 1), (0, -1), (1, 0), (-1, 0)]
for di, dj in directions:
inew, jnew = i + di, j + dj
dfs(grid, inew, jnew)
count = 0
for i in range(len(grid)):
for j in range(len(grid[0])):
if grid[i][j] == ‘1‘: # 只要存在一个就可以确定整个岛屿
count += 1
dfs(grid, i, j)
return count
由空地和墙组成的迷宫中有一个. 球可以向上下左右四个方向滚动, 但在遇到墙壁前不会停止滚动. 当球停下时, 可以选择下一个方向. 给定球的起始位置, 目的地和迷宫, 判断球能否在目的地停下. 迷宫由一个 0 和 1 的二维数组表示. 1 表示墙壁, 0 表示空地. 你可以假定迷宫的边缘都是墙壁. 起始位置和目的地的坐标通过行号和列号给出. 示例:
输入 1: 迷宫由以下二维数组表示
0 0 1 0 0
0 0 0 0 0
0 0 0 1 0
1 1 0 1 1
0 0 0 0 0
输入 2: 起始位置坐标 (rowStart, colStart) = (0, 4)
输入 3: 目的地坐标 (rowDest, colDest) = (4, 4)
输出: true
版本1 深度优先搜索
class Solution:
def hasPath(self, maze: List[List[int]], start: List[int], destination: List[int]) -> bool:
def dfs(maze, start, destination):
if start == destination:
return True
if (start[0], start[1]) in visited:
return False
visited.add((start[0], start[1]))
directions = [(1, 0), (-1, 0), (0, 1), (0, -1)]
for di, dj in directions:
i, j = start[0], start[1]
while 0 <= i + di < len(maze) and 0 <= j + dj < len(maze[0]) and maze[i + di][j + dj] == 0:
i += di
j += dj
if dfs(maze, [i, j], destination):
return True
# 只需要找到一条可行解, 所以不需要 visited.remove((start[0], start[1]))
return False
visited = set()
return dfs(maze, start, destination)
ans = Solution()
maze = [[0, 0, 1, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 1, 0],
[1, 1, 0, 1, 1],
[0, 0, 0, 0, 0]]
start = [0, 4]
destination = [3, 2]
print(ans.hasPath(maze, start, destination))
版本2 visited 集合改为直接在矩阵内修改值为 2, 此时 0 和 2 都代表 0.
class Solution:
def hasPath(self, maze: List[List[int]], start: List[int], destination: List[int]) -> bool:
if start == destination:
return True
#if (start[0], start[1]) in visited:
if maze[start[0]][start[1]] == 2:
return False
# visited.add((start[0], start[1]))
maze[start[0]][start[1]] = 2
directions = [(1, 0), (-1, 0), (0, 1), (0, -1)]
for di, dj in directions:
i, j = start[0], start[1]
while 0 <= i + di < len(maze) and 0 <= j + dj < len(maze[0]) and maze[i + di][j + dj] != 1:
i += di
j += dj
if self.hasPath(maze, [i, j], destination):
return True
return False
版本3 广度优先搜索, 队列
from typing import List
from collections import deque
class Solution:
def hasPath(self, maze: List[List[int]], start: List[int], destination: List[int]) -> bool:
queue = deque([[start[0], start[1]]])
visited = set()
# visited = {(start[0], start[1])}
directions = [(1, 0), (-1, 0), (0, 1), (0, -1)]
while queue:
i, j = queue.popleft()
if [i, j] == destination:
return True
visited.add((i, j))
for di, dj in directions:
inew, jnew = i, j
while 0 <= inew + di < len(maze) and 0 <= jnew + dj < len(maze[0]) and maze[inew + di][jnew + dj] == 0:
inew += di
jnew += dj
if (inew, jnew) in visited:
continue
queue.append([inew, jnew])
return False
标签:开始 数字 入行 cti sel jin app 有一个 填充
原文地址:https://www.cnblogs.com/funmore233/p/14610566.html