复盘|「天池 X LeetCode」在线编程专场选拔赛

复盘|「天池 X LeetCode」在线编程专场选拔赛

统计链表奇数节点

【一次遍历】遍历即可,小技巧是ans直接加0/1结果,省去if判断这一步。

1
2
3
4
5
6
7
class Solution:
def numberEvenListNode(self, head: Optional[ListNode]) -> int:
ans = 0
while head:
ans += head.val & 1
head = head.next
return ans

光线反射

【模拟】用DIRS数组存↑↓←→(对应0123四种状态)。由题意,碰到向左倾斜的镜面,←↑是一对,↓→是一对,可以通过异或操作来转换两种状态(状态 xor 2 即可,总共0123四种方向,0 xor 2=2,2 xor 2 = 0,1 xor 2 = 3,3 xor 2 = 1);碰到向右倾斜的镜面,↓←是一对,↑→是一对,同理,状态 xor 3。初始x,y = (0,0),d = 1即DIR = (1,0),然后开始模拟。

1
2
3
4
5
6
7
8
9
10
11
12
class Solution:
def getLength(self, grid: List[str], DIRS = ((-1, 0), (1, 0), (0, -1), (0, 1))) -> int:
n, m = len(grid), len(grid[0])
ans = x = y = 0
d = 1
while 0 <= x < n and 0 <= y < m:
ans += 1
if grid[x][y] == 'L': d ^= 2
elif grid[x][y] == 'R': d ^= 3
x += DIRS[d][0]
y += DIRS[d][1]
return ans

整理书架

【单调栈】要求次数尽可能少,所以要把所有出现次数大于limit的元素,删除知道出现次数=limit。要求字典序最小,所以从左往右遍历如果找到更小数字就把前面更大的数去掉。用单调栈模拟,遍历的同时,要保证栈里的元素出现次数不超过limit,如果后面没有足够的元素,也不能让元素出现次数低于limit,如果遇到比栈顶小的元素,可以出栈。代码中,入栈时候要看后面有没有足够元素。如果没足够元素(cnt[x] = limit)就continue,如果栈顶比x大且栈顶 元素也够则可以出栈。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution:
def arrangeBookshelf(self, order: List[int], limit: int) -> List[int]:
left, st, cnt_st = Counter(order), [0], Counter()
for x in order:
if cnt_st[x] == limit:
left[x] -= 1
continue
while st[-1] > x and left[st[-1]] > limit:
left[st[-1]] -= 1
cnt_st[st[-1]] -= 1
st.pop()
st.append(x)
cnt_st[x] += 1
return st[1:]

意外惊喜

【贪心 + 分治 + 01背包】由于题中说每个礼物包里的礼物价值非严格递增,所以可证不存在选了两个数组但都没有选完的情况,之多只有一个数组没有选完,其余要么整个数组都选,要么都不选。枚举这个没选完的数组,其余的转为01背包(整个数组和当作一个物品的价值,数组长度当作物品体积)。为了优化时间复杂度,需要用分治来优化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Solution:
def brilliantSurprise(self, present: List[List[int]], limit: int) -> int:
ans, dp = 0, [0] * (1 + limit)

def f(a, tot):
nonlocal dp, ans
if len(a) == 1:
sm = 0
for i, x in enumerate(a[0]):
if i >= limit: break
sm += x
ans = max(ans, dp[limit - (i + 1)] + sm)
return

tmp, m = dp.copy(), len(a) // 2
left, right = a[:m], a[m:]
for i, row in enumerate(left):
for j in range(limit, len(row) - 1, -1):
dp[j] = max(dp[j], dp[j - len(row)] + tot[i])
f(right, tot[m:])

dp = tmp
for i, row in enumerate(right, m):
for j in range(limit, len(row) - 1, -1):
dp[j] = max(dp[j], dp[j - len(row)] + tot[i])
f(left, tot[:m])

tot = [sum(a) for a in present]
f(present, tot)
return ans
欢迎关注我们的公众号
0%