目录
1. 分糖果问题(贪心思想)
单独遍历两次,先从左往右遍历(右边大的+1),再从右往左遍历(左边大的+1)
class Solution:
def candy(self , arr: List[int]) -> int:
# 记录每个位置的糖果数,每个孩子为默认为1
nums = [1] * len(arr)
# 从左到右遍历
for i in range(1, len(arr)):
# 如果右边大,则该位置糖果数为左边基础上加一
if arr[i-1] < arr[i]:
nums[i] = nums[i-1] + 1
res = nums[len(arr) - 1]
# 从右到左遍历
for i in range(len(arr)-2, -1, -1):
# 如果左边大且糖果数小,则该位置糖果数为右边基础上加一
if arr[i] > arr[i+1] and nums[i] <= nums[i+1]:
nums[i] = nums[i+1] + 1
res += nums[i]
return res
2. 主持人调度(二)(贪心思想)
排序+遍历(新开始的节目大于等于上一轮结束的时间,主持人不变,否则主持人+1)
class Solution:
def minmumNumberOfHost(self , n: int, startEnd: List[List[int]]) -> int:
start = []
end = []
for i in range(n):
start.append(startEnd[i][0])
end.append(startEnd[i][1])
start.sort()
end.sort()
res = 0
j = 0
for i in range(n):
# 新开始的节目大于等于上一轮结束的时间,主持人不变
if start[i] >= end[j]:
j += 1
else:
# 主持人+1
res += 1
return res
3. N皇后问题(递归)
class Solution:
# 判断皇后是否符合条件
def isValid(self, pos: List[int], row: int, col: int):
# 遍历记录过的行
for i in range(row):
if row == i or col == pos[i] or abs(row-i) == abs(col-pos[i]):
return False
return True
# 递归查找皇后种类
def recursion(self, n: int, row: int, pos: List[int], res: int):
if row == n:
res += 1
return res
for i in range(n):
if self.isValid(pos, row, i):
pos[row] = i
res = self.recursion(n, row + 1, pos, res)
return res
def Nqueen(self , n: int) -> int:
res = 0
# 下标为行号,元素为列号,记录皇后位置
pos = [0]*n
# 递归
result = self.recursion(n, 0, pos, res)
return result
4. 岛屿数量(dfs)
class Solution:
# 深度优先遍历
def dfs(self, grid: List[List[chr]], i: int, j: int):
n = len(grid)
m = len(grid[0])
grid[i][j] = '0'
if i - 1 >= 0 and grid[i-1][j] == '1':
self.dfs(grid, i-1, j)
if i + 1 < n and grid[i+1][j] == '1':
self.dfs(grid, i+1, j)
if j - 1 >= 0 and grid[i][j-1] == '1':
self.dfs(grid, i, j-1)
if j + 1 < m and grid[i][j+1] == '1':
self.dfs(grid, i, j+1)
def solve(self , grid: List[List[str]]) -> int:
n = len(grid)
if n == 0: return 0
m = len(grid[0])
count = 0
for i in range(n):
for j in range(m):
if grid[i][j] == '1':
count += 1
self.dfs(grid, i, j)
return count
5. 设计LRU缓存结构(哈希表+双向链表)
使用数组实现
class Solution:
def __init__(self, capacity: int):
self.capacity = capacity
self.q = []
def get(self, key: int) -> int:
flag = True
for i in range(len(self.q)):
if self.q[i][0] == key:
res = self.q[i][1]
self.q.append(self.q.pop(i))
flag = False
break
return -1 if flag else res
def set(self, key: int, value: int) -> None:
flag = True
hasKey = False
if len(self.q) >= self.capacity:
for i in range(len(self.q)):
if self.q[i][0] == key:
self.q.pop(i)
flag = False
break
if flag:
self.q.pop(0)
for i in range(len(self.q)):
if self.q[i][0] == key:
self.q[i][1] = value
hasKey = True
if not hasKey:
self.q.append([key, value])
return None
使用双向链表+双向链表实现。用哈希表的key值对应链表的节点。
# 构建双向链表结点
class Node:
def __init__(self, key, value):
self.key = key
self.value = value
self.pre = None
self.next = None
class Solution:
# 约定:链表尾的元素最新
def __init__(self, capacity: int):
self.capacity = capacity
# 双向链表头尾
self.head = Node(-1,-1)
self.tail = Node(-1,-1)
self.head.next = self.tail
self.tail.pre = self.head
# 哈希表记录Node
self.map = dict()
# 获得当前大小
def getSize(self) -> int:
cur = self.head.next
res = 0
while cur != self.tail:
cur = cur.next
res += 1
return res
# 表尾插入新元素
def insert(self, node: Node):
node.pre = self.tail.pre
node.next = self.tail
self.tail.pre.next = node
self.tail.pre = node
# 移至表尾
def moveToTail(self, node: Node):
node.pre.next = node.next
node.next.pre = node.pre
self.insert(node)
# 移除表头元素
def moveHead(self):
self.map.pop(self.head.next.key)
self.head.next.next.pre = self.head
self.head.next = self.head.next.next
def get(self, key: int) -> int:
res = -1
if key in self.map:
res = self.map[key].value
self.moveToTail(self.map[key])
return res
def set(self, key: int, value: int) -> None:
if key in self.map:
self.moveToTail(self.map[key])
self.map[key].value = value
else:
if self.getSize() >= self.capacity:
self.moveHead()
node = Node(key, value)
self.map[key] = node
self.insert(node)
6. 设计LFU缓存结构(双哈希表)
import collections
class Node:
def __init__(self, freq, key, val):
self.freq = freq
self.key = key
self.val = val
class Solution:
def __init__(self):
#记录剩余空间
self.size = 0
#key到双向链表节点的哈希表
self.mp = dict()
#频率到链表的哈希表
self.freq_mp = dict(collections.deque())
#记录当前最小频次
self.min_freq = 0
#调用函数时更新频率或者val值
def update(self, node: Node, key: int, value: int):
#找到频率
freq = node.freq
#原频率中删除该节点
self.freq_mp[freq].remove(node)
#哈希表中该频率已无节点,直接删除
if len(self.freq_mp[freq]) == 0:
self.freq_mp.pop(freq)
#若当前频率为最小,最小频率加1
if self.min_freq == freq:
self.min_freq += 1
#插入频率加一的双向链表表头,链表中对应:freq key value
node = Node(freq + 1, key, value)
if freq + 1 not in self.freq_mp:
self.freq_mp[freq + 1] = collections.deque()
self.freq_mp[freq + 1].appendleft(node)
self.mp[key] = self.freq_mp[freq + 1][0]
#set操作函数
def set(self, key:int, value: int):
#在哈希表中找到key值
if key in self.mp:
#若是哈希表中有,则更新值与频率
self.update(self.mp[key], key, value)
else:
#哈希表中没有,即链表中没有
if self.size == 0:
#满容量取频率最低且最早的删掉
oldnode = self.freq_mp[self.min_freq].pop()
#频率哈希表的链表中删除
if len(self.freq_mp[self.min_freq]) == 0:
self.freq_mp.pop(self.min_freq)
#链表哈希表中删除
self.mp.pop(oldnode.key)
#若有空闲则直接加入,容量减1
else:
self.size -= 1
#最小频率置为1
self.min_freq = 1
node = Node(1, key, value)
if 1 not in self.freq_mp:
self.freq_mp[1] = collections.deque()
self.freq_mp[1].appendleft(node)
#哈希表key值指向链表中该位置
self.mp[key] = self.freq_mp[1][0]
#get操作函数
def get(self, key: int) -> int:
res = -1
#查找哈希表
if key in self.mp:
node = self.mp[key]
#根据哈希表直接获取值
res = node.val
#更新频率
self.update(node, key, res)
return res
def LFU(self , operators: List[List[int]], k: int) -> List[int]:
res = []
#构建初始化连接
#链表剩余大小
self.size = k
#遍历所有操作
for i in range(len(operators)):
op = operators[i]
if op[0] == 1:
#set操作
self.set(op[1], op[2])
else:
#get操作
res.append(self.get(op[1]))
return resnd(self.get(op[1]))
return res
7. 螺旋矩阵(边界模拟法)
class Solution:
def spiralOrder(self , matrix: List[List[int]]) -> List[int]:
res = []
n = len(matrix)
if n == 0: return res
# 上下左右边界
left = 0
right = len(matrix[0]) - 1
up = 0
down = n - 1
while left <= right and up <= down:
# 上边界的从左到右
for i in range(left, right + 1):
res.append(matrix[up][i])
# 上边界下移
up += 1
if up > down: break
# 右边界的从上到下
for i in range(up, down + 1):
res.append(matrix[i][right])
# 右边界左移
right -= 1
if left > right: break
# 下边界的从右到左
for i in range(right, left - 1, -1):
res.append(matrix[down][i])
# 下边界上移
down -= 1
if up > down: break
# 左边界的从下到上
for i in range(down, up - 1, -1):
res.append(matrix[i][left])
# 左边界右移
left += 1
if left > right:
break
return res
8. 顺时针旋转矩阵(倒置翻转法)
class Solution:
def rotateMatrix(self , mat: List[List[int]], n: int) -> List[List[int]]:
# 矩阵转置
for i in range(n):
for j in range(i):
# 交换上三角与下三角对应的元素
mat[i][j], mat[j][i] = mat[j][i], mat[i][j]
# 每行翻转
for i in range(n):
mat[i].reverse()
return mat
9. 不同路径的数目(一)
class Solution:
def uniquePaths(self , m: int, n: int) -> int:
dp = [[0] * (n+1) for i in range(m + 1)]
for i in range(1, m + 1):
for j in range(1, n + 1):
if i == 1:
dp[i][j] = 1
continue
if j == 1:
dp[i][j] = 1
continue
dp[i][j] = dp[i-1][j] + dp[i][j-1]
return dp[m][n]
10. 矩阵最长递增路径(dfs+DP)
class Solution:
global dirs
dirs = [[-1, 0], [1, 0], [0, -1], [0, 1]]
global n, m
# 深度优先搜索,返回最大单元格数
def dfs(self, matrix: List[List[int]], dp: List[List[int]], i: int, j: int):
if dp[i][j] != 0:
return dp[i][j]
dp[i][j] += 1
for k in range(4):
nexti = i + dirs[k][0]
nextj = j + dirs[k][1]
if nexti >= 0 and nexti < n and nextj >= 0 and nextj < m and matrix[nexti][nextj] > matrix[i][j]:
dp[i][j] = max(dp[i][j], self.dfs(matrix, dp, nexti, nextj) + 1)
return dp[i][j]
def solve(self , matrix: List[List[int]]) -> int:
global n, m
if len(matrix) == 0 or len(matrix[0]) == 0:
return 0
res = 0
n = len(matrix)
m = len(matrix[0])
dp = [[0 for col in range(m)] for row in range(n)]
for i in range(n):
for j in range(m):
res = max(res, self.dfs(matrix, dp, i, j))
return res
11. 矩阵的最小路径和
class Solution:
def minPathSum(self, matrix: List[List[int]]) -> int:
n = len(matrix)
# 因为n,m均大于等于1
m = len(matrix[0])
# dp[i][j]表示以当前i,j位置为终点的最短路径长度
dp = [[0] * (m + 1) for i in range(n + 1)]
dp[0][0] = matrix[0][0]
# 处理第一列
for i in range(1, n):
dp[i][0] = matrix[i][0] + dp[i - 1][0]
# 处理第一行
for j in range(1, m):
dp[0][j] = matrix[0][j] + dp[0][j - 1]
# 其他按照公式来
for i in range(1, n):
for j in range(1, m):
if dp[i - 1][j] > dp[i][j - 1]:
dp[i][j] = matrix[i][j] + dp[i][j - 1]
else:
dp[i][j] = matrix[i][j] + dp[i - 1][j]
return dp[n - 1][m - 1]
12. 编辑距离(一)
class Solution:
def editDistance(self, str1: str, str2: str) -> int:
n1 = len(str1)
n2 = len(str2)
# dp[i][j]表示到str1[i]和str2[j]为止的子串需要的编辑距离
dp = [[0] * (n2 + 1) for i in range(n1 + 1)]
# 初始化边界
for i in range(1, n1 + 1):
dp[i][0] = dp[i - 1][0] + 1
for i in range(1, n2 + 1):
dp[0][i] = dp[0][i - 1] + 1
# 遍历第一个字符串的每个位置
for i in range(1, n1 + 1):
# 对应第二个字符串每个位置
for j in range(1, n2 + 1):
# 若是字符相同,此处不用编辑
if str1[i - 1] == str2[j - 1]:
# 直接等于二者前一个的距离
dp[i][j] = dp[i - 1][j - 1]
else:
# 选取最小的距离加上此处编辑距离1
dp[i][j] = (
min(dp[i - 1][j - 1], min(dp[i - 1][j], dp[i][j - 1])) + 1
)
return dp[n1][n2]
13. 旋转数组(平移数组:三次翻转法)
class Solution:
def solve(self , n: int, m: int, a: List[int]) -> List[int]:
# 取余,因为每次长度为n的旋转数组相当于没有变化
m = m % n
# 第一次 逆转全部数组元素
a.reverse()
b = a[:m]
# 第二次 逆转开头m个
b.reverse()
c = a[m:]
# 第三次 只逆转结尾n-m个
c.reverse()
a[:m] = b
a[m:] = c
return a