根据这个等式,可以遍历 points 所有点,使每个点作为 [x_j, y_j],并且求出满足 x_j-x_i \leq k 的最大的 (-x_i+y_i),而这一步,可以用堆来完成。用一个最小堆,堆的元素是 [x-y,x],堆顶元素的 (x-y) 值最小,即 (-x+y) 值最大。每次遍历一个点时,先弹出堆顶不满足当前 x_j-x_i \leq k 的元素,然后用堆顶元素和当前元素计算 (-x_i+y_i)+(x_j+y_j),再将当前元素放入堆。遍历完后,即得到了式子的最大值。
代码
[sol1-Python3]
1 2 3 4 5 6 7 8 9 10 11
classSolution: deffindMaxValueOfEquation(self, points: List[List[int]], k: int) -> int: res = -inf heap = [] for x, y in points: while heap and x - heap[0][1] > k: heappop(heap) if heap: res = max(res, x + y - heap[0][0]) heappush(heap, [x - y, x]) return res
[sol1-Java]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
classSolution { publicintfindMaxValueOfEquation(int[][] points, int k) { intres= Integer.MIN_VALUE; PriorityQueue<int[]> heap = newPriorityQueue<int[]>((a, b) -> a[0] - b[0]); for (int[] point : points) { intx= point[0], y = point[1]; while (!heap.isEmpty() && x - heap.peek()[1] > k) { heap.poll(); } if (!heap.isEmpty()) { res = Math.max(res, x + y - heap.peek()[0]); } heap.offer(newint[]{x - y, x}); } return res; } }
[sol1-C#]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
publicclassSolution { publicintFindMaxValueOfEquation(int[][] points, int k) { int res = int.MinValue; PriorityQueue<Tuple<int, int>, int> heap = new PriorityQueue<Tuple<int, int>, int>(); foreach (int[] point in points) { int x = point[0], y = point[1]; while (heap.Count > 0 && x - heap.Peek().Item2 > k) { heap.Dequeue(); } if (heap.Count > 0) { res = Math.Max(res, x + y - heap.Peek().Item1); } heap.Enqueue(new Tuple<int, int>(x - y, x), x - y); } return res; } }
[sol1-C++]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
classSolution { public: using pii = pair<int, int>; intfindMaxValueOfEquation(vector<vector<int>>& points, int k){ int res = INT_MIN; priority_queue<pii, vector<pii>, greater<pii>> heap; for (auto &point : points) { int x = point[0], y = point[1]; while (!heap.empty() && x - heap.top().second > k) { heap.pop(); } if (!heap.empty()) { res = max(res, x + y - heap.top().first); } heap.emplace(x - y, x); } return res; } };
funcmax(a, b int)int { if a > b { return a } return b }
funcfindMaxValueOfEquation(points [][]int, k int)int { res := -0x3f3f3f3f pq := &PriorityQueue{} for _, point := range points { x, y := point[0], point[1] for pq.Len() > 0 && x - pq.Top()[1] > k { heap.Pop(pq) } if pq.Len() > 0 { res = max(res, x + y - pq.Top()[0]) } heap.Push(pq, []int{x - y, x}) } return res }
var findMaxValueOfEquation = function (points, k) { let res = Number.MIN_SAFE_INTEGER; const heap = newMinHeap((a, b) => a[0] < b[0]); for (const point of points) { const x = point[0], y = point[1]; while (heap.size !== 0 && x - heap.peek()[1] > k) { heap.poll(); } if (heap.size !== 0) { res = Math.max(res, x + y - heap.peek()[0]); } heap.add([x - y, x]); } return res; };
classMinHeap { constructor(compareFunc = (a, b) => a < b) { this.compare = compareFunc; this.heap = []; }
时间复杂度:O(n \times \log n),其中 n 是 points 的长度,每个元素最多进入并离开 heap 一次。
空间复杂度:O(n),是 heap 的空间复杂度。
方法二:双端队列
思路
与方法一思路类似,方法一用堆来求满足 x_j-x_i \leq k 的最大的 (-x_i+y_i),而这一步可以用双端队列来求,从而降低时间复杂度。使用一个双端队列 q,元素为 [y-x,x]。每次遍历一个点时,首先同样要弹出队列头部不满足 x_j-x_i \leq k 的元素,然后用队列头部元素和当前元素计算 (y_i-x_i)+(x_j+y_j)。在当前元素进入队列尾端时,需要弹出队列末端小于等于当前 y_j-x_j 的元素,这样以来,可以使得双端队列保持递减,从而头部元素最大。然后将当前元素压入队列末端。遍历完后,即得到了式子的最大值。
代码
[sol2-Python3]
1 2 3 4 5 6 7 8 9 10 11 12 13
classSolution: deffindMaxValueOfEquation(self, points: List[List[int]], k: int) -> int: res = -inf q = deque() for x, y in points: while q and x - q[0][1] > k: q.popleft() if q: res = max(res, x + y + q[0][0]) while q and y - x >= q[-1][0]: q.pop() q.append([y - x, x]) return res
classSolution { public: using pii = pair<int, int>; intfindMaxValueOfEquation(vector<vector<int>>& points, int k){ int res = INT_MIN; deque<pii> qu; for (auto &point : points) { int x = point[0], y = point[1]; while (!qu.empty() && x - qu.front().second > k) { qu.pop_front(); } if (!qu.empty()) { res = max(res, x + y + qu.front().first); } while (!qu.empty() && y - x >= qu.back().first) { qu.pop_back(); } qu.emplace_back(y - x, x); } return res; } };
intfindMaxValueOfEquation(int** points, int pointsSize, int* pointsColSize, int k) { int res = INT_MIN; intdeque[pointsSize][2]; int head = 0, tail = 0; for (int i = 0; i < pointsSize; i++) { int x = points[i][0], y = points[i][1]; while (head != tail && x - deque[head][1] > k) { head++; } if (head != tail) { res = fmax(res, x + y + deque[head][0]); } while (head != tail && y - x >= deque[tail - 1][0]) { tail--; } deque[tail][0] = y - x; deque[tail][1] = x; tail++; } return res; }
[sol2-JavaScript]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
var findMaxValueOfEquation = function(points, k) { let res = Number.MIN_SAFE_INTEGER; const queue = []; for (const point of points) { let x = point[0], y = point[1]; while (queue.length !== 0 && x - queue[0][1] > k) { queue.shift(); } if (queue.length !== 0) { res = Math.max(res, x + y + queue[0][0]); } while (queue.length !== 0 && y - x >= queue[queue.length - 1][0]) { queue.pop(); } queue.push([y - x, x]); } return res; };