1172 words
6 minutes
日拱两卒(三)
2026-07-13

80#

划分字母区间。

把一个字符串分成尽可能多的区间,同一种字母必须出现在同一个区间。

预处理出来每个字母的最左和最右。

从前往后扫,维护必须延伸到的最右边。

class Solution:
def partitionLabels(self, s: str) -> List[int]:
n = len(s)
seg = [[-1] * 2 for _ in range(26)]
for i, ch in enumerate(s):
idx = ord(ch) - ord('a')
if seg[idx][0] == -1:
seg[idx][0] = i
seg[idx][1] = i
ans = []
l = 0
r = seg[ord(s[0]) - ord('a')][1]
i = l
while True:
if r >= n - 1:
ans.append(n - 1 - l + 1)
break
if i > r:
ans.append(r - l + 1)
l = i
r = seg[ord(s[i]) - ord('a')][1]
r = max(r, seg[ord(s[i]) - ord('a')][1])
i += 1
return ans

79#

跳跃游戏II。

问在nums上从0跳到n - 1的最小次数。每一次可以跳0nums[i]之间任意远。

记忆化做法在Leetcode上没被卡。

但本质上和80 划分字母区间是同一道题。

维护当前区间的最远延申位置,每当指针越过这个边界,就完成一次切割或者跳跃。

class Solution:
def jump(self, nums: List[int]) -> int:
n = len(nums)
if n == 1:
return 0
right = [i + nums[i] for i in range(n)]
ans = 0
r = right[0]
max_r = r
i = 0
while True:
if r >= n - 1:
ans += 1
break
if i > r:
ans += 1
r = max_r
continue
max_r = max(max_r, right[i])
i += 1
return ans

78#

跳跃游戏。

上一题的Easy版,只问能否跳到,而不问最小跳跃次数。

class Solution:
def canJump(self, nums: List[int]) -> bool:
n = len(nums)
r = 0
for i in range(n):
r = max(r, i + nums[i])
if i >= r and r != n - 1:
return False
return True

77#

买卖股票的最佳时机。

知道每一天的股票价格,问最大可能利润。简单贪心。

class Solution:
def maxProfit(self, prices: List[int]) -> int:
n = len(prices)
rmax = [0] * (n + 1)
rmax[n] = 0
for i in range(n - 1, -1, -1):
rmax[i] = max(rmax[i + 1], prices[i])
ans = 0
for i in range(n):
ans = max(ans, rmax[i] - prices[i])
return ans

76#

数据流的中位数。

往列表里不断添加元素,每添加一个元素就打印当前列表的中位数。

维护对顶堆,一个最大堆存前一半元素,一个最小堆存后一半元素,中位数只会与两个堆顶相关。

Python里有内置的堆相关内置函数,heappush是按堆的方式插元素,heappushpop是插完一个后再弹出堆顶。

默认是最小堆,想用最大堆就存相反数。

class MedianFinder:
def __init__(self):
self.left = []
self.right = []
def addNum(self, num: int) -> None:
if len(self.left) == len(self.right):
add_to_left = heappushpop(self.right, num)
heappush(self.left, -add_to_left)
else:
add_to_right = heappushpop(self.left, -num)
heappush(self.right, -add_to_right)
def findMedian(self) -> float:
if len(self.left) > len(self.right):
return -self.left[0]
return (-self.left[0] + self.right[0]) / 2

75#

前 K 个高频元素。

哈希加桶排序。

class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
cnt = {}
for num in nums:
cnt[num] = cnt.get(num, 0) + 1
max_cnt = max(cnt.values())
buckets = [[] for _ in range(max_cnt + 1)]
for x, c in cnt.items():
buckets[c].append(x)
ans = []
for bucket in reversed(buckets):
ans += bucket
if len(ans) == k:
return ans

74#

数组中的第K大元素。

快速排序的思想+每次丢掉一半。

Python里写成这种三路归并的方法应该最好理解。

处理完有[l, lt - 1] < pivot, [lt, gt] = pivot, [gt + 1, r] > pivot

class Solution:
def quick_select(self, q, l, r, k) -> int:
if l >= r:
return q[l]
pivot = q[random.randint(l, r)]
lt, i, gt = l, l, r
while i <= gt:
if q[i] < pivot:
q[i], q[lt] = q[lt], q[i]
lt += 1
i += 1
elif q[i] > pivot:
q[i], q[gt] = q[gt], q[i]
gt -= 1
else:
i += 1
if k < lt - l:
return self.quick_select(q, l, lt - 1, k)
if k <= gt - l:
return pivot
return self.quick_select(q, gt + 1, r, k - (gt - l + 1))
def findKthLargest(self, nums: List[int], k: int) -> int:
n = len(nums)
return self.quick_select(nums, 0, n - 1, n - k)

73#

柱状图重最大的矩形。

枚举高,单调栈算左右最长能延申到哪。

class Solution:
def largestRectangleArea(self, h: List[int]) -> int:
ans = 0
n = len(h)
stack = []
l = [-1] * n
for i in range(n):
while(stack and h[stack[-1]] >= h[i]):
stack.pop()
if stack:
l[i] = stack[-1]
stack.append(i)
stack = []
r = [n] * n
for i in range(n - 1, -1, -1):
while(stack and h[stack[-1]] >= h[i]):
stack.pop()
if stack:
r[i] = stack[-1]
stack.append(i)
for i in range(n):
ans = max(ans, h[i] * ((r[i] - 1) - (l[i] + 1) + 1))
return ans

72#

每日温度。

给定每一天温度,问每一天的下一个更高温度出现在几天后。

找右边第一个更大的数,单调栈经典应用。

class Solution:
def dailyTemperatures(self, temperatures: List[int]) -> List[int]:
n = len(temperatures)
ans = [0] * n
stack = []
for i in range(n - 1, -1, -1):
while stack and temperatures[stack[-1]] <= temperatures[i]:
stack.pop()
if stack:
ans[i] = stack[-1] - i
stack.append(i)
return ans

71#

字符串解码。

3[a]2[2[bc]]解析成aaabcbcbcbc

简单递归模拟。

class Solution:
def decodeString(self, s: str) -> str:
if not s:
return s
if s[0].isalpha():
return s[0] + self.decodeString(s[1:])
i = s.find('[')
n = len(s)
left = 1
for j in range(i + 1, n):
if s[j] == '[':
left += 1
elif s[j] == ']':
left -= 1
if left == 0:
return self.decodeString(s[i+1:j] * int(s[:i])) + self.decodeString(s[j+1:])