链接: 221021天池-01. 统计链表奇数节点

按题意模拟即可。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:def numberEvenListNode(self, head: Optional[ListNode]) -> int:ans = 0while head:if head.val & 1:ans += 1head = head.nextreturn ans
链接: 221021天池-02. 光线反射

DIRS=[(-1,0),(1,0),(0,-1),(0,1)],即0123分别代表上下左右 。DIRS = [(0,1),(1,0),(0,-1),(-1,0)] # →↓←↑
class Solution:def getLength(self, grid: List[str]) -> int:m, n = len(grid), len(grid[0])def inside(x,y):return 0<=x
package main// https://space.bilibili.com/206214
var dir4 = []struct{ x, y int }{{-1, 0}, {1, 0}, {0, -1}, {0, 1}}func getLength(g []string) (ans int) {n, m := len(g), len(g[0])x, y, di := 0, 0, 1for 0 <= x && x < n && 0 <= y && y < m {ans++c := g[x][y]if c == 'L' {di ^= 2} else if c == 'R' {di ^= 3}x += dir4[di].xy += dir4[di].y}return
}
链接: 221021天池-03. 整理书架

class Solution:def arrangeBookshelf(self, order: List[int], limit: int) -> List[int]:cnt = Counter(order)st = []used = Counter()for i,v in enumerate(order):if used[v] < limit:while st and st[-1] > v and cnt[st[-1]]+used[st[-1]]>limit:used[st.pop()] -= 1used[v] += 1st.append(v)cnt[v] -= 1return st
链接: 221021天池-04. 意外惊喜

class Solution:def brilliantSurprise(self, present: List[List[int]], limit: int) -> int: """1. 由于每个礼包内价值是递增的,我们发现最终的拿取方案中绝对不可能存在两个或以上的礼包都只拿一部分。证明如下:假设存在两个都没拿完的礼包,这两个礼包拿取得最后一个价值分别是ai和bj,那么只存在两种情况:ai==bj 或 ai>bj(如果aib[j],我们知道价值递增,那么a[i+1]>=a[i]>b[j]>=b[j-1],即a[i+1]必>b[j],那么我们可以放弃b[j],换取a[i+1],会使答案更优;当a[i]==b[j],我们知道价值内部递增,那么a[i+1]>=a[i]==b[j]>=b[j-1],因此我们可以放弃b[j],换取a[i+1]不会使答案更差。2. 因此最终的选取方案一定是只存在0个或1个礼包拿一部分,其它的要么拿全部要么不拿3. 也就是说其它的可以当01背包计算。体积是本行的len,价值是本行sum4. 01背包复杂度O(n*limit) 再枚举n个数组,那就O(n*n*limit)过不了,因此要想办法重复利用背包的计算结果。5. 这里是分治来优化的。注意在同一层时,需要分别对left求01背包,计算right;对right求01背包,计算left;这两部分的dp前提是一样的,因此要还原DP状态。6. 总体时间复杂度O(limit*n*lgn)"""
# 3928 msdp = [0]*(limit+1) # 01背包空间压缩写法,dp[j]代表开了j个箱子的最大价值ans = 0total = [sum(row) for row in present]def f(l,r): # 递归的区间左右端点,避免切片nonlocal ans, dp if l == r: # 最后一个单独的礼包作为没用完那个s = 0for i,v in enumerate(present[l][:limit],start = 1):s += vans = max(ans, s + dp[limit-i])returnmid = (l+r) // 2 # 分治tmp = dp[:] # 保留案发现场# 01背包左边,递归右边for i in range(l,mid+1):for j in range(limit, len(present[i]) - 1, -1):dp[j] = max(dp[j], dp[j-len(present[i])]+total[i])f(mid+1, r)dp = tmp # 还原案发现场# 01背包右边,递归左边for i in range(mid+1, r+1):for j in range(limit, len(present[i]) - 1, -1):dp[j] = max(dp[j], dp[j-len(present[i])]+total[i])f(l, mid)f(0, len(present)-1)return ans# 4080ms
# dp = [0]*(limit+1) # 空间压缩的01背包,dp[i]开了i次礼物的最大价值
# ans = 0
# def f(pr,total): # 当前处理的礼包区间,total对应的区间
# nonlocal ans,dp
# if len(pr) == 1: # 区间只剩一个礼包的话,这个就作为最后开的那个没开完的礼包
# s = 0
# for i,v in enumerate(pr[0],start=1):
# if i > limit:break
# s += v
# ans = max(ans,dp[limit-i]+s)
# return # tmp = dp.copy() # 保留案发现场
# mid = len(pr) // 2
# left, right = pr[:mid], pr[mid:]# # 背包左边,处理右边;两种写法都可以 枚举的同样的东西
# # # 4020 ms
# # for i,v in enumerate(total[:mid]):
# # for j in range(limit,len(pr[i])-1,-1):
# # dp[j] = max(dp[j],dp[j-len(pr[i])] + v)
# # # 4080 ms
# for i,row in enumerate(left):
# for j in range(limit,len(row)-1,-1):
# dp[j] = max(dp[j],dp[j-len(row)]+total[i])
# f(right,total[mid:])# dp = tmp # 还原案发现场
# # 背包右边,处理左边
# # for i,v in enumerate(total[mid:], mid):
# # for j in range(limit,len(pr[i])-1,-1):
# # dp[j] = max(dp[j],dp[j-len(pr[i])] + v)
# for i,row in enumerate(right,mid):
# for j in range(limit,len(row)-1,-1):
# dp[j] = max(dp[j],dp[j-len(row)]+total[i])
# f(left,total[:mid])# total = [sum(row) for row in present]
# f(present,total)
# return ans
下一篇:网络安全红队常用的攻击方法及路径