本题可以发现一些枚举的技巧,在枚举多个值的时候,自己有时候脑袋晕晕的,会把变量的更新顺序搞混,此时,可以用依赖树来解决。
如同本题:
class Solution: def maximumTripletValue(self, nums: List[int]) -> int: res = pre_max = pre_dif = 0 for x in nums: res = max(res, pre_dif * x) pre_dif = max(pre_dif, pre_max - x) pre_max = max(pre_max, x) '''
res -> pre_dif -> pre_max 按照拓扑序来更新变量就不会出问题
''' return res
我们可以将一个数组无限的拼起来,找到元素和为target的最小子数组,可以预想在 nums + nums + nums + ... 这样的数组中做滑动窗口
1 2 3 | 1 2 3 | 1 2 3...
可以发现我们在滑动窗口时,窗口内的元素由多个nums和一个前缀和一个后缀组成。
窗口内的nums个数为: target // sum(nums)
所以本题在分析到这里后,只要考虑前一个nums的前缀和后一个nums的后缀(这个后缀可能是跨过了nums),其实就是在 nums + nums这个大数组中,任意地方插入我们 target//sum(nums)个nums就是答案。
class Solution: def minSizeSubarray(self, nums: List[int], target: int) -> int: total = sum(nums) n = len(nums) ans = inf left = 0 s = 0 for right in range(n * 2): s += nums[right % n] while s > target % total: s -= nums[left % n] left += 1 if s == target % total: ans = min(ans, right - left + 1) if ans == inf: return -1 return ans + target // total * n
这个题目给的图有个特点,出度都是1,且有n个点n条边,是一个内向基环树。
处理基环树问题时,首先是要找环,可以使用拓扑排序来找环。
有向图中可以建立反向边,从入度为0的点开始进行拓扑排序,最后那几个点度数不会为0,不会被加入队列;无向图中度数为2的那些点就是基环上的点。
本题我们先建立反向边找到基环,然后从基环上的点进行遍历。
基环上的点可达的点数就是环的大小。基环外的子树可达的点就是其到基环点的距离+基环大小。这个距离就是其到基环的深度。
class Solution: ''' 每个点都只有一条出边, 并且有n个点,n条边,是内向基环图 ''' def countVisitedNodes(self, g: List[int]) -> List[int]: n = len(g) rg = [[] for _ in range(n)] deg = [0] * n for x, y in enumerate(g): rg[y].append(x) deg[y] += 1 q = deque(i for i, d in enumerate(deg) if d == 0) while q: x = q.popleft() y = g[x] deg[y] -= 1 if deg[y] == 0: q.append(y) ans = [0] * n def rdfs(x: int, depth: int) -> None: ans[x] = depth for y in rg[x]: if deg[y] == 0: # 是树枝边 rdfs(y, depth + 1) for i, d in enumerate(deg): if d <= 0: continue ring = [] x = i while True: deg[x] = -1 ring.append(x) x = g[x] if x == i: break for x in ring: rdfs(x, len(ring)) return ans
标签:pre,周赛,target,nums,int,max,基环树,365,deg From: https://www.cnblogs.com/zk6696/p/17805688.html