DeepSeek LeetCode 2030. 含特定字母的最小子序列 Python3实现
·
以下是 LeetCode 2030 的 Python3 实现,采用与 Java 版本相同的单调栈 + 贪心 + 后缀预处理策略。
class Solution:
def smallestSubsequence(self, s: str, k: int, letter: str, repetition: int) -> str:
n = len(s)
# 后缀中 letter 的数量
suffix = [0] * (n + 1)
for i in range(n - 1, -1, -1):
suffix[i] = suffix[i + 1] + (1 if s[i] == letter else 0)
stack = [] # 模拟栈
letter_in_stack = 0 # 栈中 letter 的数量
for i, c in enumerate(s):
# 尝试弹出栈顶以获得更小的字典序
while stack and stack[-1] > c:
top = stack[-1]
rest = n - i # 剩余可用的字符数(包括当前字符)
if top == letter:
# 弹出 letter 后,能否满足长度和 letter 数量要求
if (letter_in_stack - 1 + suffix[i] >= repetition
and len(stack) - 1 + rest >= k):
stack.pop()
letter_in_stack -= 1
else:
break
else:
if len(stack) - 1 + rest >= k:
stack.pop()
else:
break
# 当前字符入栈
stack.append(c)
if c == letter:
letter_in_stack += 1
# 截取前 k 个字符
res = stack[:k]
# 统计当前 letter 数量,若不足则从后向前修改非 letter 字符
cnt = sum(1 for ch in res if ch == letter)
need = repetition - cnt
if need > 0:
# 转为列表方便修改
arr = list(res)
for i in range(len(arr) - 1, -1, -1):
if need == 0:
break
if arr[i] != letter:
arr[i] = letter
need -= 1
res = arr
return ''.join(res)
思路解析
-
后缀预处理
使用suffix数组记录每个位置之后(包括自身)的letter数量,用于快速判断弹出栈顶letter后,后续字符是否还能补齐repetition个letter。 -
单调栈贪心
- 遍历字符串
s,维护一个单调递增栈(栈底到栈顶的字典序尽可能小)。 - 当前字符
c比栈顶小时,若弹出栈顶后仍能用剩余字符凑足长度k和所需letter数量,则弹出栈顶(让更小的字符占据更靠前的位置)。 - 弹出判断需区分栈顶是否为
letter,因为涉及letter的数量约束。
- 遍历字符串
-
截断与补足
- 因栈可能大于
k,直接取前k个字符。 - 若此时
letter数量不足,从结果末尾开始,将非letter字符改为letter。这样做对字典序的影响最小(因为修改发生在更靠后的位置)。
- 因栈可能大于
复杂度
- 时间:
O(n),每个字符最多入栈、出栈一次。 - 空间:
O(n),用于后缀数组和栈。
更多推荐



所有评论(0)