LC 3357. 最小化相邻元素的最大差值
https://leetcode.cn/problems/minimize-the-maximum-adjacent-element-difference/description/
这题看了 题解 ,感觉解决过程有点意思,主要的突破点是把X和Y尝试固定下来,主框架还是使用二分搜索。
假设我们选择出来了X, Y. 先要区分中间是一个-1,还是两个-1.
- 如果是一个-1的话,那么只需要检查X, Y是否满足
- 如果里面是两个-1的话,那么还需要检查Y-X是否满足条件。
至于如何选择X, Y.
- 我们可以先把所有可能的边界值全部列举出来,这些边界值的宽度都是 `2*k`
- X一定是 `min(a) + k`. 而Y去尝试选择最大的,但是X没有办法覆盖的,下边界值,这样选择的理由是
- 可以尽可能确保Y可以覆盖X没有办法覆盖到的范围。
- 同时选择下边界值值确保X, Y之间可以尽可能满足条条件。
- 本质上这里还是使用贪心算法。
class Solution: def minDifference(self, nums: List[int]) -> int: def test(arr, k): border = [] for l, c, r in arr: if c > 1 and (r - l) > 3 * k: return False border.append((l - k, l + k)) border.append((r - k, r + k)) border.sort() # choose X x = border[0][1] # choose Y y = border[0][0] for l, r in border: if x < l: y = max(y, l) # print(border, k, x, y) def ok(l, c, r): if abs(l - x) <= k and abs(r - x) <= k: return True if abs(l - y) <= k and abs(r - y) <= k: return True if c > 1: if (y - x) > k: return False if abs(l - x) <= k and abs(r - y) <= k: return True return False # right now (Y-X) maybe > k # but we can check if we can cover only with X for l, c, r in arr: if not ok(l, c, r): return False return True s, e = 0, max(nums) # arr -> list[(left, how many -1, right)] # left, right could be -1 arr, l, cnt = [], -1, 0 for i in range(len(nums)): if nums[i] == -1: cnt += 1 continue if cnt != 0: arr.append((l, cnt, nums[i])) cnt = 0 l = nums[i] if i > 0 and nums[i - 1] != -1: s = max(s, abs(nums[i - 1] - nums[i])) if (i + 1) < len(nums) and nums[i + 1] != -1: s = max(s, abs(nums[i + 1] - nums[i])) if cnt != 0: arr.append((l, cnt, -1)) if not arr: return s if len(arr) == 1 and (arr[0], arr[-1]) == (-1, -1): return 0 for i in range(len(arr)): l, cnt, r = arr[i] l = l if l != -1 else r r = r if r != -1 else l if l > r: l, r = r, l arr[i] = (l, cnt, r) # print(arr) while s <= e: m = (s + e) // 2 ok = test(arr, m) # print(ok) if ok: e = m - 1 else: s = m + 1 return s