欢迎关注我的CSDN:https://spike.blog.csdn.net/
本文地址:https://spike.blog.csdn.net/article/details/144744418
LeetCode 合计最常见的 102 题:
- 校招100题 第1天 链表(List) (15题)
- 校招100题 第2天 树(Tree) (20题)
- 校招100题 第3天 动态规划(DP) (20题)
- 校招100题 第4天 查找排序(Search&Sort) (12题)
- 校招100题 第5天 双指针(Two Pointers) (11题)
- 校招100题 第6天 回溯法(Backtracking) (8题)
- 校招100题 第7天 序列(数据结构&贪心) (14题)
- 校招100题 第8天 图(Graph) (2题)
序列(数据结构&贪心) 算法包括栈、字典、集合、贪心等,基于不同的数据存储和访问方式的数据结构。栈(Stack) 是一种 后进先出(LIFO) 的数据结构,支持 推入(append) 和 弹出(pop) 操作,常用于处理嵌套问题和回溯算法。字典(Map) 是一种基于键值对的存储结构,提供快速的查找、插入和删除操作,其效率通常与哈希表的实现有关。集合(Set) 是一种无序且元素唯一的数据结构,支持高效的成员检查、添加和删除操作,常用于去重和数学集合操作。
1. 栈
1.1 32. 最长有效括号 (Hard)
Lintcode: 193 · 最长有效括号,牛客常考题⭐️
class Solution:
def longestValidParentheses(self, s: str) -> int:
"""
最长有效括号, stack+flags更清晰,格式正确且连续,时间O(n), 空间O(n)
"""
n = len(s)
if n <= 1:
return 0
flags = [False] * n
stack = []
for i in range(n):
if s[i] == "(":
stack.append(i)
else:
if stack:
j = stack.pop(-1)
flags[i] = flags[j] = True
res = 0
tmp = 0
for f in flags:
if f:
tmp += 1
res = max(res, tmp)
else:
tmp = 0
return res
1.2 394. 字符串解码
LintCode:575 · 字符串解码
class Solution:
def decodeString(self, s: str) -> str:
"""
栈操作,类似3[a]2[bc],时间O(S+|s|),空间复杂度O(S)
"""
stack = []
res = ""
for c in s:
if c != "]": # 不等于
stack.append(c)
continue
tmp = "" # 解码"]"
while stack and stack[-1] != "[":
item = stack.pop(-1)
tmp += item[::-1] # 内部需要翻转,防止嵌套括号
tmp = tmp[::-1] # 整体进行翻转
stack.pop()
v = ""
while stack and stack[-1].isdigit():
item = stack.pop(-1)
v += item[::-1]
v = v[::-1]
tmp = tmp * int(v)
stack.append(tmp)
res = "".join(stack)
return res
1.3 739. 每日温度
LintCode:1060 · 每日温度
class Solution:
def dailyTemperatures(self, temperatures: List[int]) -> List[int]:
"""
最高温度出现在第几天之后,索引,输入列表,返回列表。
单调栈,当前大于栈内最大值,则更新结果之后出栈
时间O(n),空间O(n)
"""
nums = temperatures
n = len(nums)
stack = [] # 单调栈
res = [0] * n
for i in range(n):
while stack and nums[stack[-1]] < nums[i]:
tmp = stack.pop()
res[tmp] = i - tmp
stack.append(i)
return res
2. 集合
2.1 128. 最长连续序列
LintCode:124 · 最长连续序列,牛客常考题⭐️
class Solution:
def longestConsecutive(self, nums: List[int]) -> int:
"""
最长连续序列,不考虑顺序,只考虑是否+1(连续),哈希表,依次判断是否存在,
时间O(N),空间O(N)
"""
res = 0
v_set = set(nums)
for v in v_set:
if (v-1) in v_set:
continue
tmp = v # 连续值
r_tmp = 1
while (tmp+1) in v_set:
tmp += 1
r_tmp += 1
res = max(res, r_tmp)
return res
2.2 14. 最长公共前缀
LintCode: 78 · 最长公共前缀,牛客常考题⭐️
class Solution:
def longestCommonPrefix(self, strs: List[str]) -> str:
"""
最长公共前缀,时间O(N),空间O(M)
"""
res = ""
n_list = []
for s in strs:
n_list.append(len(s))
n_min = min(n_list)
for i in range(n_min):
tmp = set()
for s in strs:
tmp.add(s[i])
if len(tmp) == 1:
res += list(tmp)[0]
else:
break
return res
3. 字典
3.1 560. 和为 K 的子数组 (前缀和PreSum)
LintCode:838 · 子数组和为K,牛客常考题⭐️
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
"""
前缀和 + 哈希表优化: pre[i]-pre[j-1]=k -> pre[j-1]=pre[i]-k
pre[i]是前n项的和, pre[j-1]是之前出现的和,统计哈希表中pre[j-1]出现的次数,即可。
输入:nums = [1,2,3], k = 3,输出:2,谨记: 数组不是单调的话,不要用滑动窗口,考虑用前缀和
时间复杂度O(N), 空间O(N)
"""
n = len(nums)
presum = 0 # presum[i],前缀值
res = 0
mp = collections.defaultdict(int) # 统计前缀值出现的次数
mp[0] = 1 # 注意,初始化前缀值0是1
for i in range(n):
presum += nums[i]
tmp = presum - k # pre[j-1]的值
if tmp in mp.keys(): # 这个值出现过,加入这个值出现的次数
res += mp[tmp]
mp[presum] += 1 # 加入新值
return res
4. 贪心
4.1 55. 跳跃游戏
LintCode:116 · 跳跃游戏
class Solution:
def canJump(self, nums: List[int]) -> bool:
"""
跳跃游戏1,是否成功,贪心,最大跳跃长度,超越数组,时间O(n),空间O(1)
nums = [3,2,1,0,4],输出:false
"""
n = len(nums)
if n == 1:
return True
v_max = 0 # 到达的最远距离
for i in range(n-1):
if i > v_max:
return False
v_max = max(v_max, nums[i]+i) # nums[i]+i 跳跃的最大长度
if v_max >= n-1: # 大于最后一个位置
return True
return True if v_max >= n-1 else False
4.2 45. 跳跃游戏 II
LintCode:117 · 跳跃游戏 II
class Solution:
def jump(self, nums: List[int]) -> int:
"""
跳跃游戏2,最小跳跃次数,贪心,时间O(n),空间O(1)
nums[i]是从索引i向前跳转的 最大 长度
"""
n = len(nums)
if n == 1:
return 0
v_max = 0 # 到达的最远距离
end = 0
res = 0
for i in range(n-1):
if i > v_max: # 小于一次最远位置
return -1
v_max = max(v_max, nums[i]+i) # 当前最远的位置
if i == end: # i到达边界步数
end = v_max # 更新最大边界,同时跳跃次数+1
res += 1 # 步数+1,一次一次的更新
return res
4.3 134. 加油站
LintCode:187 · 加油站
class Solution:
def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
"""
运行环路一周,贪心算法,gas是加油数量,cost是花费,选择起始位置
gas = [1,2,3,4,5], cost = [3,4,5,1,2], 输出: 3
燃料最低点的下一个开始,时间O(n), 空间O(1)
"""
n = len(gas)
v_min = float("inf")
i_min = 0 # 燃料最低点的位置
tmp = 0
for i in range(n):
tmp += gas[i] - cost[i] # 累计剩余燃料
if tmp <= v_min: # 保存剩余燃料最低值
v_min = tmp
i_min = i
if tmp < 0:
return -1
return (i_min+1) % n # 最低燃料的下一个开始
4.4 121. 买卖股票的最佳时机
LintCode:149 · 买卖股票的最佳时机,牛客常考题⭐️
class Solution:
def maxProfit(self, prices: List[int]) -> int:
"""
买卖股票1,只在一只赚钱,时间O(n),空间O(1)
输入:[7,1,5,3,6,4],输出:5
"""
prev = prices[0]
res = 0
n = len(prices)
for i in range(n):
res = max(res, prices[i]-prev)
prev = min(prev, prices[i])
return res
4.5 122. 买卖股票的最佳时机 II
LintCode:150 · 买卖股票的最佳时机 II,牛客常考题⭐️
class Solution:
def maxProfit(self, prices: List[int]) -> int:
"""
买卖股票2,赚差价,贪心,累加区间最大值,时间O(n),空间O(1)
输入:prices = [1,2,3,4,5],输出:4
"""
n = len(prices)
res = 0
for i in range(1, n):
res += max(0, prices[i]-prices[i-1])
return res
4.6 LCR 158. 库存管理 II(超过半数的数字)
牛客常考题⭐️
class Solution:
def inventoryManagement(self, stock: List[int]) -> int:
"""
数组中出现超过一半的数字(众数)
摩尔投票法: 核心理念为 票数正负抵消。 时间O(N), 空间O(1)
"""
nums = stock
n = len(nums)
v = 0 # 众数
tmp = 0 # 投票,当投票是0时,替换新的数字
for i in range(n):
if tmp == 0:
v = nums[i]
if nums[i] == v:
tmp += 1
else:
tmp -= 1
res = 0 # 统计次数
for i in range(n):
if nums[i] == v:
res += 1
if res > (n//2):
return v
else:
return 0
5. 矩阵模拟
5.1 48. 旋转图像
LintCode:161 · 旋转图像
class Solution:
def rotate(self, matrix: List[List[int]]) -> None:
"""
上下翻转、对角线翻转,顺时针旋转90°,即是旋转图像
逆时针旋转90°是左右翻转
时间O(n^2),空间O(1)
"""
if not matrix or not matrix[0]:
return
m = len(matrix)
n = len(matrix[0])
# 上下翻转,如果是水平翻转(n-j-1),则逆时针旋转90°
for i in range(m//2):
for j in range(n):
matrix[i][j], matrix[m-i-1][j] = matrix[m-i-1][j], matrix[i][j]
# 对角矩阵翻转
for i in range(m):
for j in range(i):
matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
5.2 54. 螺旋矩阵
LintCode:374 · 螺旋矩阵,牛客常考题⭐️
class Solution:
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
"""
4个指针 + 上右不用判断,下左需要判断边界,时间O(mn), 空间O(1), 空间排除输出之外的复杂度
"""
if not matrix or not matrix[0]:
return []
m = len(matrix)
n = len(matrix[0])
res = []
l, r, t, b = 0, n-1, 0, m-1
while l <= r and t <= b:
for i in range(l, r+1):
res.append(matrix[t][i])
for i in range(t+1, b+1):
res.append(matrix[i][r])
# 非常重要的边界判断,否则会重复
if l < r and t < b:
for i in range(r-1, l-1, -1):
res.append(matrix[b][i])
for i in range(b-1, t, -1):
res.append(matrix[i][l])
l += 1
r -= 1
t += 1
b -= 1
return res