由於刪除後左右兩邊的數字都要是遞增的,因此我們可以先計算出 nums 的前綴以及 pre 和後綴 suf
pre[i] 代表 nums[:i+1] 是否滿足遞增。
suf[i] 代表 nums[i:] 是否滿足遞增。
刪除後仍是遞增,代表刪除後的左右子陣列都是遞增的,且左子陣列的最後一個元素小於右子陣列的第一個元素。因此枚舉要刪除的子陣列的左右邊界 i 和 j,檢查 pre[i−1]、suf[j+1] 是否為 1,且 nums[i−1]<nums[j+1] 是否成立即可。注意一些邊界情況。
時間複雜度 O(n2)
空間複雜度 O(n)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
classSolution: defincremovableSubarrayCount(self, nums: List[int]) -> int: defcheck(i, j): cur = nums[:i] + nums[j + 1:] nn = len(cur) for k inrange(nn - 1): if cur[k] >= cur[k + 1]: returnFalse returnTrue n = len(nums) ans = 0 for i inrange(n): for j inrange(i, n): if check(i, j): ans += 1 return ans
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
classSolution: defincremovableSubarrayCount(self, nums: List[int]) -> int: n = len(nums) pre = [1] for i inrange(1, n): x = 1if nums[i] > nums[i - 1] and pre[-1] else0 pre.append(x) suf = [1] for i inrange(n - 2, -1, -1): x = 1if nums[i] < nums[i + 1] and suf[-1] else0 suf.append(x) suf = suf[::-1] ans = 0 for i inrange(n): for j inrange(i, n): if (i-1 < 0or pre[i-1] == 1) and (j+1 >= n or suf[j+1] == 1) and (i-1 < 0or j+1 >= n or nums[i-1] < nums[j+1]): ans += 1 return ans
classSolution: deflargestPerimeter(self, nums: List[int]) -> int: n = len(nums) nums.sort() # pre = list(accumulate(nums, initial=0)) s = sum(nums) for i inrange(n - 1, 1, -1): # if pre[i] > nums[i]: # return pre[i] + nums[i] if s > 2 * nums[i]: # s - nums[i] > nums[i] return s s -= nums[i] return -1
classSolution: defincremovableSubarrayCount(self, nums: List[int]) -> int: n = len(nums) pre = [1] for i inrange(1, n): x = 1if nums[i] > nums[i - 1] and pre[-1] else0 pre.append(x) suf = [1] for i inrange(n - 2, -1, -1): x = 1if nums[i] < nums[i + 1] and suf[-1] else0 suf.append(x) suf = suf[::-1]
i = pre.count(1) - 1# 前綴最長遞增陣列的最後一個元素的下標 if i == n - 1: return n * (n + 1) // 2 ans = i + 2# 可以移除 [0,n-1], [1,n-1], ..., [i+1, n-1] 的子陣列 j = n - 1 while j > 0and suf[j] == 1: # 枚舉右端點 while i >= 0and nums[i] >= nums[j]: # 左端點太大了,移動左端點 i -= 1 ans += i + 2# 可以移除 [0,j-1], [1,j-1], ..., [i+1, j-1] 的子陣列 j -= 1 return ans
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
classSolution: defincremovableSubarrayCount(self, nums: List[int]) -> int: n = len(nums) i = 0 while i < n - 1and nums[i] < nums[i + 1]: # 先確定前綴的最長遞增陣列的最後一個元素的下標 i += 1 if i == n - 1: # 特判,整個陣列都是遞增的,代表每個子陣列都是可以被移除的 return n * (n + 1) // 2
ans = i + 2# 可以移除 [0,n-1], [1,n-1], ..., [i+1, n-1] 的子陣列 j = n - 1 while j == n - 1or nums[j] < nums[j + 1]: # 枚舉右端點 while i >= 0and nums[i] >= nums[j]: # 左端點太大了,移動左端點 i -= 1 ans += i + 2# 可以移除 [0,j-1], [1,j-1], ..., [i+1, j-1] 的子陣列 j -= 1 return ans
classSolution: defplacedCoins(self, edges: List[List[int]], cost: List[int]) -> List[int]: n = len(cost) g = defaultdict(list) for u, v in edges: # 無向圖 g[u].append(v) g[v].append(u)
ans = [1] * n # 初始化答案為1,即子樹中傑點數量 < 3 的情況
defdfs(u, fa): res = 1# 子樹中的節點數量 hp1 = [-cost[u]] if cost[u] > 0else [] # 正數,MaxHeap hp2 = [cost[u]] if cost[u] <= 0else [] # 負數,MinHeap for v in g[u]: if v != fa: x, res_hp1, res_hp2 = dfs(v, u) res += x hp1.extend(res_hp1) hp2.extend(res_hp2) # Heap heapify(hp1) # O(n) heapify(hp2) # O(n) hp1 = sorted(hp1[:7])[:3] # 只取前3大正數,取前3層做排序 hp2 = sorted(hp2[:3])[:2] # 只取前2小負數,取前2層做排序 # 排序 # hp1 = sorted(hp1)[:3] # 只取前3大正數 # hp2 = sorted(hp2)[:2] # 只取前2小負數 if res >= 3: tmp1 = tmp2 = float('-inf') iflen(hp1) >= 3: # 三正 tmp1 = -hp1[0] * -hp1[1] * -hp1[2] iflen(hp1) >= 1andlen(hp2) >= 2: # 一正兩負 tmp2 = -hp1[0] * hp2[0] * hp2[1] ans[u] = max(0, tmp1, tmp2) # 剩餘情況都是負數,根據題意,放0 return res, hp1, hp2 dfs(0, -1) return ans