1、找到字符串中所有字母的异位词
给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。
示例 1:
输入: s = "cbaebabacd", p = "abc"
输出: [0,6]
解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。
示例 2:
输入: s = "abab", p = "ab"
输出: [0,1,2]
解释:
起始索引等于 0 的子串是 "ab", 它是 "ab" 的异位词。
起始索引等于 1 的子串是 "ba", 它是 "ab" 的异位词。
起始索引等于 2 的子串是 "ab", 它是 "ab" 的异位词。
class Solution:
def findAnagrams(self, s: str, p: str) -> list[int]:
ans = []
target_map = [0] * 26
n, m = len(s), len(p)
# 如果s比p小,则不会存在答案
if n < m:
return ans
# 统计p中字符出现次数
for ch in p:
idx = ord(ch) - ord('a')
target_map[idx] += 1
# 滑动窗口指针初始化
left = right = 0
# 滑动窗口内的字符出现次数
window_map = [0] * 26
while right < n:
# 当right触发窗口条件,即窗口大小大于p的长度
if right - left >= m:
# 比较窗口内与目标字符,相等则添加入答案
if window_map == target_map:
ans.append(left)
# 移动left满足窗口条件,并将left处字符数量减1
idx = ord(s[left]) - ord('a')
window_map[idx] -= 1
left += 1
# 将right处的字符加入统计
idx = ord(s[right]) - ord('a')
window_map[idx] += 1
right += 1
# 最后需判断right == n时,滑动窗口是否符合条件
if window_map == target_map:
ans.append(left)
return ans
if __name__ == '__main__':
solu = Solution()
s = "cbaebabacd"
p = "abc"
print(solu.findAnagrams(s,p))
2、乘积小于 k 的子数组
给定一个正整数数组 nums和整数 k 。请找出该数组内乘积小于 k 的连续的子数组的个数。
示例 1:
输入: nums = [10,5,2,6], k = 100
输出: 8
解释: 8个乘积小于100的子数组分别为: [10], [5], [2], [6], [10,5], [5,2], [2,6], [5,2,6]。
需要注意的是 [10,5,2] 并不是乘积小于100的子数组。
示例 2:
输入: nums = [1,2,3], k = 0
输出: 0
class Solution:
def numSubarrayProductLessThanK(self, nums: list[int], k: int) -> int:
L, R = 0, 0
ans = 0
num = nums[0]
while L < len(nums) and R < len(nums):
if num < k:
ans += R - L + 1
R += 1
if R < len(nums):
num *= nums[R]
else:
num /= nums[L]
L += 1
return ans
if __name__ == '__main__':
solu = Solution()
nums = [10,5,2,6]
3、长度最小的子数组
给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
示例 1:
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
示例 2:
输入:target = 4, nums = [1,4,4]
输出:1
示例 3:
输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0
from math import inf
class Solution:
def minSubArrayLen(self, target: int, nums: list[int]) -> int:
low, fast = 0, 0
n = len(nums)
count, num = 0, float('inf') # 设定 num 的最大值为无穷大利用 min 去降低
for i in range(n):
count += nums[i]
while count >= target:
num = min(i - low + 1, num) # i-low+1 表示区间长度
count -= nums[low] # 去除区间最左端的值,滑动窗口整体右移
low += 1
return num if num != inf else 0
if __name__ == '__main__':
solu = Solution()
nums = [2,3,1,2,4,3]
target = 7
print(solu.minSubArrayLen(target,nums))
4、岛屿数量
给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。
示例 1:
输入:grid = [
["1","1","1","1","0"],
["1","1","0","1","0"],
["1","1","0","0","0"],
["0","0","0","0","0"]
]
输出:1
示例 2:
输入:grid = [
["1","1","0","0","0"],
["1","1","0","0","0"],
["0","0","1","0","0"],
["0","0","0","1","1"]
]
输出:3
# 方法一: DFS
class Solution:
def numIslands(self, grid: list[list[str]]) -> int:
n, m = len(grid), len(grid[0])
count = 0
def Dfs(x, y):
grid[x][y] = '0' # 标记查询过的陆地为水面
for num in [[0, 1], [0, -1], [1, 0], [-1, 0]]: # 前后左右遍历陆地
nx, ny = x + num[0], y + num[1]
if 0 <= nx < n and 0 <= ny < m and grid[nx][ny] == '1':
Dfs(nx, ny) # 递归查询
for i in range(n):
for j in range(m):
if grid[i][j] == '1':
Dfs(i, j)
count += 1
return count
# 方法二: BFS
"""
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
count = 0
for row in range(len(grid)):
for col in range(len(grid[0])):
if grid[row][col] == '1': # 发现陆地
count += 1 # 结果加1
grid[row][col] = '0' # 将其转为 ‘0’ 代表已经访问过
# 对发现的陆地进行扩张即执行 BFS,将与其相邻的陆地都标记为已访问
# 下面还是经典的 BFS 模板
land_positions = collections.deque()
land_positions.append([row, col])
while len(land_positions) > 0:
x, y = land_positions.popleft()
for new_x, new_y in [[x, y + 1], [x, y - 1], [x + 1, y], [x - 1, y]]: # 进行四个方向的扩张
# 判断有效性
if 0 <= new_x < len(grid) and 0 <= new_y < len(grid[0]) and grid[new_x][new_y] == '1':
grid[new_x][new_y] = '0' # 因为可由 BFS 访问到,代表同属一块岛,将其置 ‘0’ 代表已访问过
land_positions.append([new_x, new_y])
return count
"""
5、省份数量
有 n 个城市,其中一些彼此相连,另一些没有相连。如果城市 a 与城市 b 直接相连,且城市 b 与城市 c 直接相连,那么城市 a 与城市 c 间接相连。
省份 是一组直接或间接相连的城市,组内不含其他没有相连的城市。
给你一个 n x n 的矩阵 isConnected ,其中 isConnected[i][j] = 1 表示第 i 个城市和第 j 个城市直接相连,而 isConnected[i][j] = 0 表示二者不直接相连。
返回矩阵中 省份 的数量。
示例 1:
输入:isConnected = [[1,1,0],[1,1,0],[0,0,1]]
输出:2
示例 2:
输入:isConnected = [[1,0,0],[0,1,0],[0,0,1]]
输出:3
# 方法一:BFS
import collections
class Solution:
@staticmethod
def findCircleNum(isConnected: list[list[int]]) -> int:
provinces = len(isConnected)
visited = set()
circles = 0
for i in range(provinces):
if i not in visited:
Q = collections.deque([i])
while Q:
j = Q.popleft()
visited.add(j)
for k in range(provinces):
if isConnected[j][k] == 1 and k not in visited:
Q.append(k)
circles += 1
return circles
if __name__ == '__main__':
solu = Solution()
isConnected = [[1, 1, 0], [1, 1, 0], [0, 0, 1]]
print(solu.findCircleNum(isConnected))
"""
方法二 :DFS
visited = set()
n = len(isConnected)
# 将i所在的省份加入visited
def dfs(i):
for j in range(n):
# 这里加入 j not in visited 的判断特别重要
# 加上这句话 如果每一个j都出现在里visited中 则不会向下递归 不加则无穷向下递归
if isConnected[i][j] == 1 and j not in visited:
visited.add(j)
dfs(j)
# 遍历所有的城市
num_prov = 0
for i in range(n):
# 如果i不在之前遍历过的省份
if i not in visited:
num_prov += 1
# 将i所在省份的城市纳入visited
dfs(i)
return num_prov
"""
6、被围绕的区域
给你一个 m x n 的矩阵 board ,由若干字符 'X' 和 'O' ,找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O' 用 'X' 填充。
示例 1:
输入: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"]]
解释:被围绕的区间不会存在于边界上,换句话说,任何边界上的 'O' 都不会被填充为 'X'。 任何不在边界上,或不与边界上的 'O' 相连的 'O' 最终都会被填充为 'X'。如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。
示例 2:
输入:board = [["X"]]
输出:[["X"]]
class Solution:
def solve(self, board: list[list[str]]) -> None:
"""
Do not return anything, modify board in-place instead.
"""
m, n = len(board), len(board[0])
if not board:
return
if m < 3 or n < 3:
return
def DFS(i, j):
if i < 0 or i >= m or j < 0 or j >= n or board[i][j] != 'O':
return
board[i][j] = '#'
for ch in [[1, 0], [-1, 0], [0, -1], [0, 1]]:
nx, ny = ch[0] + i, ch[1] + j
DFS(nx, ny)
for i in range(m):
DFS(i, 0)
DFS(i, n-1)
for j in range(n):
DFS(0, j)
DFS(m -1 , j)
for i in range(m):
for j in range(n):
if board[i][j] == "O":
board[i][j] = "X"
if board[i][j] == "#":
board[i][j] = "O"
return board
if __name__ == '__main__':
solu = Solution()
#board = [["X","X","X","X"],["X","O","O","X"],["X","X","O","X"],["X","O","X","X"]]
#board = [["O","O","O"],["O","O","O"],["O","O","O"]]
board = [["X","O","X","O","X","O"],["O","X","O","X","O","X"],["X","O","X","O","X","O"],["O","X","O","X","O","X"]]
print(solu.solve(board))
"""
下面代码有些问题还在修改
# 如果是空数组,直接返回
# Leetcode总搞这种边边角角的输入
if not board: return
# 计算数组长宽
row = len(board)
col = len(board[0])
# 如果长度或者宽度中一个小于3的话也不用算了,直接返回
if row < 3 or col < 3:
return
# DFS函数
def dfs(i, j):
# 如果i,j中有一个越界或者遇到了X则不继续扫描
if i < 0 or j < 0 or i >= row or j >= col or board[i][j] != 'O':
return
# 否则把数组中的O变成#,意思是这个O和边缘是连通的
board[i][j] = '#'
# 之后从当前坐标开始上下左右进行递归搜索
for ch in [[0, 1], [0, -1], [1, 0], [-1, 0]]:
nx , ny = i + ch[0], j + ch[1]
dfs(nx,ny)
for i in range(row):
# 搜索第一行和最后一行
dfs(0, i)
dfs(row - 1, i)
for i in range(col):
# 搜索第一列和最后一列
dfs(i, 0)
dfs(i, col - 1)
# 全部搜索完毕后:
# X X X X
# X X O X
# X O X X
# X O X X
# 变为:
# X X X X
# X X O X
# X # X X
# X # X X
# 之后再将所有的#变成O,O变成X就可以了
for i in range(0, row):
for j in range(0, col):
if board[i][j] == 'O':
board[i][j] = 'X'
if board[i][j] == '#':
board[i][j] = 'O'
"""