LeetCode周赛第343场:激烈角逐,谁是下一位排列之王?
2023-01-21 11:59:02
第 343 场 LeetCode 单周赛:贪心算法与字符串匹配的精彩对决
简介
欢迎来到第 343 场 LeetCode 单周赛的精彩回顾!在这个紧张刺激的角逐中,参赛者们大显身手,运用贪心构造、字符串匹配、图论、字符串操作和动态规划等算法,解决了一系列富有挑战性的难题。
贪心构造的艺术:下一个排列
第一题“下一个排列”考察了参赛者的贪心构造能力。给定一个数字序列,参赛者需要找到该序列的“下一个排列”,即比当前序列更大的下一个序列,且使用最小的字典序。贪心算法的精髓在于,每一步都选择最优的局部解,最终得到最优的全局解。这道题正是对贪心算法的深刻考验。
代码示例:
def nextPermutation(nums):
i = len(nums) - 2
# 从右向左找到第一个降序元素
while i >= 0 and nums[i] >= nums[i + 1]:
i -= 1
# 如果没有降序元素,则序列已经是最后一个排列,反转即可
if i < 0:
nums.reverse()
return
# 找到大于 nums[i] 的最右侧元素
j = len(nums) - 1
while j >= 0 and nums[j] <= nums[i]:
j -= 1
# 交换 nums[i] 和 nums[j]
nums[i], nums[j] = nums[j], nums[i]
# 反转 nums[i + 1:]
nums[i + 1:] = sorted(nums[i + 1:])
字符串匹配的利器:按顺序查找字符
第二题“按顺序查找字符”考察了参赛者的字符串匹配能力。给定一个字符串和一个模式串,参赛者需要找出模式串在字符串中的所有出现位置。滑动窗口算法是解决这道题的有效方法。滑动窗口算法的思路是,将模式串作为一个窗口,在字符串中移动,每移动一步,检查窗口内的字符是否与模式串匹配。如果匹配,则记录下窗口的起始位置。
代码示例:
def findAnagrams(s, p):
# 记录 p 中各字符出现的次数
char_count = Counter(p)
# 记录窗口内各字符出现的次数
window = Counter()
# 结果列表
result = []
# 遍历字符串 s
for i in range(len(s)):
# 更新窗口
window[s[i]] += 1
# 窗口大小等于模式串长度时
if i >= len(p):
window[s[i - len(p)]] -= 1
if window[s[i - len(p)]] == 0:
del window[s[i - len(p)]]
# 窗口中各字符出现的次数与模式串相同时
if window == char_count:
result.append(i - len(p) + 1)
return result
图论的挑战:最长异或路径
第三题“最长异或路径”考察了参赛者的图论知识。给定一张无向图,参赛者需要找到一条从起点到终点的路径,使得路径上的所有边的异或值的最大。动态规划算法可以有效地解决这道题。动态规划算法的思路是,将问题分解成一系列子问题,然后逐步解决这些子问题,最终得到问题的整体解。
代码示例:
def longestXorPath(graph, start, end):
# 初始化 dp 表
dp = [[0 for _ in range(1 << 16)] for _ in range(len(graph))]
# 设置起点状态
dp[start][0] = 1
# 遍历所有节点
for node in range(len(graph)):
# 遍历所有异或值
for xor_value in range(1 << 16):
# 更新状态
for neighbor in graph[node]:
dp[neighbor][xor_value ^ graph[node][neighbor]] = max(dp[neighbor][xor_value ^ graph[node][neighbor]], dp[node][xor_value] + 1)
# 返回结果
return dp[end][0]
字符串操作的妙用:重新排列字符串使相邻字符不同
第四题“重新排列字符串使相邻字符不同”考察了参赛者的字符串操作能力。给定一个字符串,参赛者需要将字符串中的字符重新排列,使得相邻的字符不同。哈希表是解决这道题的有效方法。哈希表是一种数据结构,可以快速地查找和插入元素。参赛者可以利用哈希表来记录字符串中每个字符出现的次数,然后根据字符出现的次数来重新排列字符串。
代码示例:
def rearrangeCharacters(s):
# 记录字符出现的次数
char_count = Counter(s)
# 将字符按出现次数降序排序
char_list = sorted(char_count.items(), key=lambda x: x[1], reverse=True)
# 重新排列字符串
result = []
for char, count in char_list:
for i in range(count):
if len(result) == 0 or result[-1] != char:
result.append(char)
else:
# 如果相邻字符相同,则插入一个不同的字符
for j in range(len(result)):
if result[j] != char:
result[j], result[-1] = result[-1], result[j]
break
return ''.join(result)
动态规划的巅峰:最长特殊序列 IV
第五题“最长特殊序列 IV”考察了参赛者的动态规划能力。给定一个字符串和一个目标字符串,参赛者需要找到字符串中包含目标字符串的最长特殊序列。特殊序列是指字符串中连续的一段子串,且子串中的每个字符都不同。动态规划算法可以有效地解决这道题。动态规划算法的思路是,将问题分解成一系列子问题,然后逐步解决这些子问题,最终得到问题的整体解。
代码示例:
def longestSpecialSubsequence(s, target):
# 初始化 dp 表
dp = [[0 for _ in range(len(s) + 1)] for _ in range(len(target) + 1)]
# 遍历字符串 s
for i in range(len(s)):
# 遍历目标字符串 target
for j in range(len(target)):
# 如果当前字符相等,则更新 dp 值
if s[i] == target[j]:
dp[j + 1][i + 1] = dp[j][i] + 1
# 否则,取最大值
else:
dp[j + 1][i + 1] = max(dp[j + 1][i], dp[j][i + 1])
# 返回结果
return dp[-1][-1]
结论
第 343 场 LeetCode 单周赛再次展现了算法之美。参赛者们运用各种算法,从贪心构造到动态规划,解决了五道具有挑战性的题目。希望这篇文章能帮助大家深入理解这些算法,并激发你们解决更多算法难题的兴趣。
常见问题解答
-
什么是贪心算法?
- 贪心算法是一种分步求解问题的算法,每一步都选择最优的局部解,最终得到全局最优解。
-
什么是字符串匹配?
- 字符串匹配是指在给定的字符串中找到另一个字符串的出现位置。
-
什么是滑动窗口算法?
- 滑动窗口算法是一种字符串匹配算法,将模式串作为一个窗口,在字符串中移动,检查窗口内的字符是否与模式串匹配。
-
什么是动态规划算法?
- 动态规划算法是一种解决优化问题的算法,将问题分解成一系列子问题,然后逐步解决这些子问题,最终得到问题的整体解。
-
什么是哈希表?
- 哈希表是一种数据结构,可以快速地查找和插入元素。哈希表将元素映射到一个键,键的值可以是元素本身或元素的索引。