目录
79. 单词搜索
class Solution:
def exist(self, board: List[List[str]], word: str) -> bool:
# 使用深度优先搜索
if not board: # 边界条件
return False
for i in range(len(board)):
for j in range(len(board[0])):
if self.dfs(board, i, j, word):
return True
return False
def dfs(self, board, i, j, word):
if len(word) == 0: # 如果单词已经检查完毕
return True
if i < 0 or i >= len(board) or j < 0 or j >= len(board[0]) or word[0] != board[i][j]: # 如果路径出界或者矩阵中的值不是word的首字母,返回False
return False
tmp = board[i][j] # 如果找到了第一个字母,检查剩余的部分
board[i][j] = '0'
res = self.dfs(board,i+1,j,word[1:]) or self.dfs(board,i-1,j,word[1:]) or self.dfs(board,i,j+1,word[1:]) or self.dfs(board, i, j-1, word[1:]) # 上下左右四个方向搜索
board[i][j] = tmp # 标记过的点恢复原状,以便进行下一次搜索
return res
class Solution:
# (x-1,y)
# (x,y-1) (x,y) (x,y+1)
# (x+1,y)
directions = [(0, -1), (-1, 0), (0, 1), (1, 0)]
def exist(self, board: List[List[str]], word: str) -> bool:
m = len(board)
if m == 0:
return False
n = len(board[0])
marked = [[False for _ in range(n)] for _ in range(m)]
for i in range(m):
for j in range(n):
# 对每一个格子都从头开始搜索
if self.__search_word(board, word, 0, i, j, marked, m, n):
return True
return False
def __search_word(self, board, word, index,
start_x, start_y, marked, m, n):
# 先写递归终止条件
if index == len(word) - 1:
return board[start_x][start_y] == word[index]
# 中间匹配了,再继续搜索
if board[start_x][start_y] == word[index]:
# 先占住这个位置,搜索不成功的话,要释放掉
marked[start_x][start_y] = True
for direction in self.directions:
new_x = start_x + direction[0]
new_y = start_y + direction[1]
# 注意:如果这一次 search word 成功的话,就返回
if 0 <= new_x < m and 0 <= new_y < n and \
not marked[new_x][new_y] and \
self.__search_word(board, word,
index + 1,
new_x, new_y,
marked, m, n):
return True
marked[start_x][start_y] = False
return False
class Solution {
public:
bool exist(vector<vector<char>>& board, string word) {
if(board.size() == 0) return false;
for (int i=0;i<board.size();i++){
for(int j=0;j<board[0].size();j++){
if (dfs(board,word,i,j,0)){
return true;
}
}
}
return false;
}
bool dfs(vector<vector<char>>& board, string& word, int i,int j,int length){
if(i>=board.size()||j>=board[0].size()||i<0||j<0||length>=word.size()||word[length]!=board[i][j]){
return false;
}
if(length==word.size()-1&&word[length]==board[i][j]){
return true;
}
char temp=board[i][j];
board[i][j]='0';
bool flag=dfs(board,word,i,j+1,length+1)||dfs(board,word,i,j-1,length+1)||dfs(board,word,i+1,j,length+1)||dfs(board,word,i-1,j,length+1);
board[i][j]=temp; // 标记过的点恢复原状,以便进行下一次搜索
return flag;
}
};
85. 最大矩形
class Solution:
def maximalRectangle(self, matrix: List[List[str]]) -> int:
if not matrix:
return 0
# 定义最大矩形面积函数
def largeRectangle(arr):
arr = [0] + arr + [0]
stack = []
res = 0
for i in range(len(arr)):
while stack and arr[stack[-1]] > arr[i]:
tmp = stack.pop()
res = max(res, (i - stack[-1] -1) * arr[tmp])
stack.append(i)
return res
hight = [0] * len(matrix[0])
result = 0
for raw in range(len(matrix)):
for col in range(len(matrix[0])):
if matrix[raw][col] == '1':
hight[col] += 1
else:
hight[col] = 0
result = max(result, largeRectangle(hight))
return result
221. 最大正方形
动态规划:
此外,还需要考虑边界条件。如果 i 和 j 中至少有一个为 0,则以位置 (i, j) 为右下角的最大正方形的边长只能是 1,因此 dp(i, j) = 1。
class Solution:
def maximalSquare(self, matrix: List[List[str]]) -> int:
if len(matrix) == 0 or len(matrix[0]) == 0:
return 0
maxSide = 0
rows, columns = len(matrix), len(matrix[0])
dp = [[0] * columns for _ in range(rows)]
for i in range(rows):
for j in range(columns):
if matrix[i][j] == '1':
if i == 0 or j == 0:
dp[i][j] = 1
else:
dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1
maxSide = max(maxSide, dp[i][j])
maxSquare = maxSide * maxSide
return maxSquare
1277. 统计全为 1 的正方形子矩阵
此题同221题
class Solution:
def countSquares(self, matrix: List[List[int]]) -> int:
m, n = len(matrix), len(matrix[0])
f = [[0] * n for _ in range(m)]
ans = 0
for i in range(m):
for j in range(n):
if i == 0 or j == 0:
f[i][j] = matrix[i][j]
elif matrix[i][j] == 0:
f[i][j] = 0
else:
f[i][j] = min(f[i][j - 1], f[i - 1][j], f[i - 1][j - 1]) + 1
ans += f[i][j]
return ans
130. 被围绕的区域
本题给定的矩阵中有三种元素:
字母 X;
被字母 X 包围的字母 O;
没有被字母 X 包围的字母 O。
本题要求将所有被字母 X 包围的字母 O都变为字母 X ,但很难判断哪些 O 是被包围的,哪些 O 不是被包围的。
注意到题目解释中提到:任何边界上的 O 都不会被填充为 X。 我们可以想到,所有的不被包围的 O 都直接或间接与边界上的 O 相连。我们可以利用这个性质判断 O 是否在边界上,具体地说:
对于每一个边界上的 O,我们以它为起点,标记所有与它直接或间接相连的字母 O;
最后我们遍历这个矩阵,对于每一个字母:
如果该字母被标记过,则该字母为没有被字母 X 包围的字母 O,我们将其还原为字母 O;
如果该字母没有被标记过,则该字母为被字母 X 包围的字母 O,我们将其修改为字母 X。
DFS:
class Solution:
def solve(self, board: List[List[str]]) -> None:
"""
Do not return anything, modify board in-place instead.
"""
if not board:
return
n, m = len(board), len(board[0])
def dfs(x, y):
if not 0 <= x < n or not 0 <= y < m or board[x][y] != 'O':
return
board[x][y] = "A"
dfs(x + 1, y)
dfs(x - 1, y)
dfs(x, y + 1)
dfs(x, y - 1)
for i in range(n):
dfs(i, 0)
dfs(i, m - 1)
for i in range(m - 1):
dfs(0, i)
dfs(n - 1, i)
for i in range(n):
for j in range(m):
if board[i][j] == "A":
board[i][j] = "O"
elif board[i][j] == "O":
board[i][j] = "X"
class Solution {
public:
int n, m;
void dfs(vector<vector<char>>& board, int x, int y) {
if (x < 0 || x >= n || y < 0 || y >= m || board[x][y] != 'O') {
return;
}
board[x][y] = 'A';
dfs(board, x + 1, y);
dfs(board, x - 1, y);
dfs(board, x, y + 1);
dfs(board, x, y - 1);
}
void solve(vector<vector<char>>& board) {
n = board.size();
if (n == 0) {
return;
}
m = board[0].size();
for (int i = 0; i < n; i++) {
dfs(board, i, 0);
dfs(board, i, m - 1);
}
for (int i = 1; i < m - 1; i++) {
dfs(board, 0, i);
dfs(board, n - 1, i);
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (board[i][j] == 'A') {
board[i][j] = 'O';
} else if (board[i][j] == 'O') {
board[i][j] = 'X';
}
}
}
}
};
200. 岛屿数量
class Solution:
directions = [(-1, 0), (0, -1), (1, 0), (0, 1)]
def numIslands(self, grid: List[List[str]]) -> int:
m = len(grid)
# 特判
if m == 0:
return 0
n = len(grid[0])
marked = [[False for _ in range(n)] for _ in range(m)]
count = 0
# 从第 1 行、第 1 格开始,对每一格尝试进行一次 DFS 操作
for i in range(m):
for j in range(n):
# 只要是陆地,且没有被访问过的,就可以使用 DFS 发现与之相连的陆地,并进行标记
if not marked[i][j] and grid[i][j] == '1':
# count 可以理解为连通分量,你可以在深度优先遍历完成以后,再计数,
# 即这行代码放在【位置 1】也是可以的
count += 1
self.__dfs(grid, i, j, m, n, marked)
# 【位置 1】
return count
def __dfs(self, grid, i, j, m, n, marked):
marked[i][j] = True
for direction in self.directions:
new_i = i + direction[0]
new_j = j + direction[1]
if 0 <= new_i < m and 0 <= new_j < n and not marked[new_i][new_j] and grid[new_i][new_j] == '1':
self.__dfs(grid, new_i, new_j, m, n, marked)
695. 岛屿的最大面积
class Solution:
def maxAreaOfIsland(self, grid: List[List[int]]) -> int:
m, n = len(grid), len(grid[0])
def dfs(gird, i, j):
if 0<=i<m and 0<=j<n and grid[i][j]:
grid[i][j] = 0
return 1 + dfs(grid, i+1,j) + dfs(grid, i-1, j) + dfs(grid, i, j+1) + dfs(grid, i, j-1)
return 0
result = 0
for x in range(m):
for y in range(n):
result = max(result, dfs(grid, x, y))
return result
class Solution:
def dfs(self, grid, cur_i, cur_j):
if cur_i < 0 or cur_j < 0 or cur_i == len(grid) or cur_j == len(grid[0]) or grid[cur_i][cur_j] != 1:
return 0
grid[cur_i][cur_j] = 0
ans = 1
for di, dj in [[0, 1], [0, -1], [1, 0], [-1, 0]]:
next_i, next_j = cur_i + di, cur_j + dj
ans += self.dfs(grid, next_i, next_j)
return ans
def maxAreaOfIsland(self, grid: List[List[int]]) -> int:
ans = 0
for i, l in enumerate(grid):
for j, n in enumerate(l):
ans = max(self.dfs(grid, i, j), ans)
return ans
class Solution {
int dfs(vector<vector<int>>& grid, int cur_i, int cur_j) {
if (cur_i < 0 || cur_j < 0 || cur_i == grid.size() || cur_j == grid[0].size() || grid[cur_i][cur_j] != 1)
return 0;
grid[cur_i][cur_j] = 0;
int di[4] = {0, 0, 1, -1};
int dj[4] = {1, -1, 0, 0};
int ans = 1;
for (int index = 0; index != 4; ++index) {
int next_i = cur_i + di[index], next_j = cur_j + dj[index];
ans += dfs(grid, next_i, next_j);
}
return ans;
}
public:
int maxAreaOfIsland(vector<vector<int>>& grid) {
int ans = 0;
for (int i = 0; i != grid.size(); ++i)
for (int j = 0; j != grid[0].size(); ++j)
ans = max(ans, dfs(grid, i, j));
return ans;
}
};
463. 岛屿的周长
直接遍历,如果当前值为1,加4(四条边),如果左边有1,减2(两条边重合),上面有1,减2。
最后相加即可.
class Solution {
public:
int islandPerimeter(vector<vector<int>>& grid) {
int res = 0;
for (int row = 0; row <= (int)grid.size() - 1; row++)
{
for (int col = 0; col <= (int)grid[0].size() - 1; col++)
{
if (grid[row][col])
{
if (0 == row || 0 == grid[row - 1][col]) // 前一个不是
{
res += 2;
}
if (0 == col || 0 == grid[row][col - 1]) // 上一行不是
{
res += 2;
}
}
}
}
return res;
}
};
class Solution:
def islandPerimeter(self, grid: List[List[int]]) -> int:
res=0
for i in range(len(grid)):
for j in range(len(grid[0])):
if grid[i][j]==1:
res+=4
if i-1>=0 and grid[i-1][j]==1:
res-=2
if j-1>=0 and grid[i][j-1]==1:
res-=2
return res
827. 最大人工岛
class Solution:
def largestIsland(self, grid: List[List[int]]) -> int:
def dfs(i,j,grid,newnumber):
if i<0 or i>m-1 or j<0 or j>n-1:
return 0
if grid[i][j] != 1:
return 0
grid[i][j] = newnumber
return 1+dfs(i-1,j,grid,newnumber)+dfs(i,j-1,grid,newnumber)+dfs(i+1,j,grid,newnumber)+dfs(i,j+1,grid,newnumber)
m = len(grid)
n = len(grid[0])
newnumber = 1
area = {}
maxarea = 0
for i in range(m):
for j in range(n):
if grid[i][j] == 1:
newnumber+=1
area[newnumber] = dfs(i,j,grid,newnumber)
maxarea = max(maxarea,area[newnumber])
maxareares = 0
for i in range(m):
for j in range(n):
if grid[i][j] == 0:
areares = 1
res = []
if i+1<m :
res.append(grid[i+1][j])
if i-1>=0:
res.append(grid[i-1][j])
if j+1<n:
res.append(grid[i][j+1])
if j-1>=0:
res.append(grid[i][j-1])
res = list(set(res))
for k in range(len(res)):
areares += area.get(res[k],0)
maxareares = max(maxareares,areares)
return max(maxareares,maxarea)
1293. 网格中的最短路径
广度优先搜索:
class Solution:
def shortestPath(self, grid: List[List[int]], k: int) -> int:
m, n = len(grid), len(grid[0])
if m == 1 and n == 1:
return 0
k = min(k, m + n - 3)
visited = set([(0, 0, k)])
q = collections.deque([(0, 0, k)])
step = 0
while len(q) > 0:
step += 1
cnt = len(q)
for _ in range(cnt):
x, y, rest = q.popleft()
for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
nx, ny = x + dx, y + dy
if 0 <= nx < m and 0 <= ny < n:
if grid[nx][ny] == 0 and (nx, ny, rest) not in visited:
if nx == m - 1 and ny == n - 1:
return step
q.append((nx, ny, rest))
visited.add((nx, ny, rest))
elif grid[nx][ny] == 1 and rest > 0 and (nx, ny, rest - 1) not in visited:
q.append((nx, ny, rest - 1))
visited.add((nx, ny, rest - 1))
return -1
更精简的代码:
class Solution:
def shortestPath(self, grid: List[List[int]], k: int) -> int:
if not any(grid):
return -1
m, n = len(grid), len(grid[0])
k = min(k, m+n-3)
q = [(0, 0, k, 0)]
visited = {(0, 0, k)}
while q:
x, y, rest, steps = q.pop(0)
if x == m-1 and y == n-1:
return steps
for nx, ny in [(x+1, y), (x-1, y), (x, y+1), (x, y-1)]:
if 0 <= nx < m and 0 <= ny < n:
nk = rest-grid[nx][ny]
if nk < 0 or (nx, ny, nk) in visited:
continue
q.append((nx, ny, nk, steps+1))
visited.add((nx, ny, nk))
return -1
62. 不同路径
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
dp = [[1]*n] + [[1]+[0] * (n-1) for _ in range(m-1)]
#print(dp)
for i in range(1, m):
for j in range(1, n):
dp[i][j] = dp[i-1][j] + dp[i][j-1]
return dp[-1][-1]
64. 最小路径和
class Solution:
def minPathSum(self, grid: List[List[int]]) -> int:
if not grid or not grid[0]:
return 0
rows, columns = len(grid), len(grid[0])
dp = [[0] * columns for _ in range(rows)]
dp[0][0] = grid[0][0]
for i in range(1, rows):
dp[i][0] = dp[i - 1][0] + grid[i][0]
for j in range(1, columns):
dp[0][j] = dp[0][j - 1] + grid[0][j]
for i in range(1, rows):
for j in range(1, columns):
dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j]
return dp[rows - 1][columns - 1]
741. 摘樱桃
动态规划:
class Solution:
def cherryPickup(self, grid: List[List[int]]) -> int:
N = len(grid)
memo = [[[None] * N for _1 in range(N)] for _2 in range(N)]
def dp(r1, c1, c2):
r2 = r1 + c1 - c2
if (N == r1 or N == r2 or N == c1 or N == c2 or
grid[r1][c1] == -1 or grid[r2][c2] == -1):
return float('-inf')
elif r1 == c1 == N-1:
return grid[r1][c1]
elif memo[r1][c1][c2] is not None:
return memo[r1][c1][c2]
else:
ans = grid[r1][c1] + (c1 != c2) * grid[r2][c2]
ans += max(dp(r1, c1+1, c2+1), dp(r1+1, c1, c2+1),
dp(r1, c1+1, c2), dp(r1+1, c1, c2))
memo[r1][c1][c2] = ans
return ans
return max(0, dp(0, 0, 0))
120. 三角形最小路径和
方法一:自顶向下动态规划
class Solution:
def minimumTotal(self, triangle: List[List[int]]) -> int:
n = len(triangle)
f = [[0] * n for _ in range(n)]
f[0][0] = triangle[0][0]
for i in range(1, n):
f[i][0] = f[i - 1][0] + triangle[i][0]
for j in range(1, i):
f[i][j] = min(f[i - 1][j - 1], f[i - 1][j]) + triangle[i][j]
f[i][i] = f[i - 1][i - 1] + triangle[i][i]
return min(f[n - 1])
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
int n = triangle.size();
vector<vector<int>> f(n, vector<int>(n));
f[0][0] = triangle[0][0];
for (int i = 1; i < n; ++i) {
f[i][0] = f[i - 1][0] + triangle[i][0];
for (int j = 1; j < i; ++j) {
f[i][j] = min(f[i - 1][j - 1], f[i - 1][j]) + triangle[i][j];
}
f[i][i] = f[i - 1][i - 1] + triangle[i][i];
}
return *min_element(f[n - 1].begin(), f[n - 1].end());
}
};
方法二:自底向上
class Solution:
def minimumTotal(self, triangle: List[List[int]]) -> int:
dp = triangle[-1]
for i in range(len(triangle)-2,-1,-1):
for j in range(i+1):
dp[j] = triangle[i][j] + min(dp[j],dp[j+1])
return dp[0]
542. 01 矩阵
方法1:BFS
class Solution:
def updateMatrix(self, matrix: List[List[int]]) -> List[List[int]]:
m, n = len(matrix), len(matrix[0])
dist = [[0] * n for _ in range(m)]
zeroes_pos = [(i, j) for i in range(m) for j in range(n) if matrix[i][j] == 0]
# 将所有的 0 添加进初始队列中
q = collections.deque(zeroes_pos)
seen = set(zeroes_pos)
# 广度优先搜索
while q:
i, j = q.popleft()
for ni, nj in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]:
if 0 <= ni < m and 0 <= nj < n and (ni, nj) not in seen:
dist[ni][nj] = dist[i][j] + 1
q.append((ni, nj))
seen.add((ni, nj))
return dist
方法2:动态规划
class Solution:
def updateMatrix(self, matrix: List[List[int]]) -> List[List[int]]:
m, n = len(matrix), len(matrix[0])
# 初始化动态规划的数组,所有的距离值都设置为一个很大的数
dist = [[10**9] * n for _ in range(m)]
# 如果 (i, j) 的元素为 0,那么距离为 0
for i in range(m):
for j in range(n):
if matrix[i][j] == 0:
dist[i][j] = 0
# 只有 水平向左移动 和 竖直向上移动,注意动态规划的计算顺序
for i in range(m):
for j in range(n):
if i - 1 >= 0:
dist[i][j] = min(dist[i][j], dist[i - 1][j] + 1)
if j - 1 >= 0:
dist[i][j] = min(dist[i][j], dist[i][j - 1] + 1)
# 只有 水平向左移动 和 竖直向下移动,注意动态规划的计算顺序
for i in range(m - 1, -1, -1):
for j in range(n):
if i + 1 < m:
dist[i][j] = min(dist[i][j], dist[i + 1][j] + 1)
if j - 1 >= 0:
dist[i][j] = min(dist[i][j], dist[i][j - 1] + 1)
# 只有 水平向右移动 和 竖直向上移动,注意动态规划的计算顺序
for i in range(m):
for j in range(n - 1, -1, -1):
if i - 1 >= 0:
dist[i][j] = min(dist[i][j], dist[i - 1][j] + 1)
if j + 1 < n:
dist[i][j] = min(dist[i][j], dist[i][j + 1] + 1)
# 只有 水平向右移动 和 竖直向下移动,注意动态规划的计算顺序
for i in range(m - 1, -1, -1):
for j in range(n - 1, -1, -1):
if i + 1 < m:
dist[i][j] = min(dist[i][j], dist[i + 1][j] + 1)
if j + 1 < n:
dist[i][j] = min(dist[i][j], dist[i][j + 1] + 1)
return dist
class Solution:
def updateMatrix(self, matrix: List[List[int]]) -> List[List[int]]:
m, n = len(matrix), len(matrix[0])
# 初始化动态规划的数组,所有的距离值都设置为一个很大的数
dist = [[10**9] * n for _ in range(m)]
# 如果 (i, j) 的元素为 0,那么距离为 0
for i in range(m):
for j in range(n):
if matrix[i][j] == 0:
dist[i][j] = 0
# 只有 水平向左移动 和 竖直向上移动,注意动态规划的计算顺序
for i in range(m):
for j in range(n):
if i - 1 >= 0:
dist[i][j] = min(dist[i][j], dist[i - 1][j] + 1)
if j - 1 >= 0:
dist[i][j] = min(dist[i][j], dist[i][j - 1] + 1)
# 只有 水平向右移动 和 竖直向下移动,注意动态规划的计算顺序
for i in range(m - 1, -1, -1):
for j in range(n - 1, -1, -1):
if i + 1 < m:
dist[i][j] = min(dist[i][j], dist[i + 1][j] + 1)
if j + 1 < n:
dist[i][j] = min(dist[i][j], dist[i][j + 1] + 1)
return dist
1162. 地图分析
BFS:
def maxDistance(self, grid: List[List[int]]) -> int:
N = len(grid)
queue = []
# 将所有的陆地格子加入队列
for i in range(N):
for j in range(N):
if grid[i][j] == 1:
queue.append((i, j))
# 如果我们的地图上只有陆地或者海洋,请返回 -1。
if len(queue) == 0 or len(queue) == N * N:
return -1
distance = -1
while len(queue) > 0:
distance += 1
# 这里一口气取出 n 个结点,以实现层序遍历
n = len(queue)
for i in range(n):
r, c = queue.pop(0)
# 遍历上边单元格
if r-1 >= 0 and grid[r-1][c] == 0:
grid[r-1][c] = 2
queue.append((r-1, c))
# 遍历下边单元格
if r+1 < N and grid[r+1][c] == 0:
grid[r+1][c] = 2
queue.append((r+1, c))
# 遍历左边单元格
if c-1 >= 0 and grid[r][c-1] == 0:
grid[r][c-1] = 2
queue.append((r, c-1))
# 遍历右边单元格
if c+1 < N and grid[r][c+1] == 0:
grid[r][c+1] = 2
queue.append((r, c+1))
return distance
更精简的代码:
class Solution:
def maxDistance(self, grid: List[List[int]]) -> int:
n = len(grid)
steps = -1
queue = [(i, j) for i in range(n) for j in range(n) if grid[i][j] == 1]
if len(queue) == 0 or len(queue) == n ** 2: return steps
while len(queue) > 0:
for _ in range(len(queue)):
x, y = queue.pop(0)
for xi, yj in [(x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)]:
if xi >= 0 and xi < n and yj >= 0 and yj < n and grid[xi][yj] == 0:
queue.append((xi, yj))
grid[xi][yj] = -1
steps += 1
return steps