LC 1014. Best Sightseeing Pair
https://leetcode.com/problems/best-sightseeing-pair/
这题目我一开始就陷入了过去归并排序的思路。这种思路不复杂,并且时间复杂度对N<=50000应该是可以的。
我们定义两个序列: a: [A[i] + i] 和 b: [A[j] - j], 然后对a, b做归并排序。 在合并的过程中,可以看到a和b的最大值都在末尾,这样我们直接相加就好了。
另外因为A[i] <= 1000,说明我们其实不用归并长度超过1000的两个序列。 因为a的最后一个元素的下标是i, 那么b最后一个元素下标肯定>i+1000, 这样
- A[i] + i + A[j] - j <
- A[i] + A[j] - (i-j) <
- A[i] + A[j] - 1000 <=
- A[i]
兴致勃勃地写了觉得巨牛的程序,提交上去发现2980ms。加上长度1000这个优化也只是2492ms。 另外还有一个有趣的发现是,使用 `sorted` 直接排序比自己手写归并排序要快,可以到1168ms.
class Solution: def maxScoreSightseeingPair(self, A: List[int]) -> int: n = len(A) a = [A[i] + i for i in range(n)] b = [A[i] - i for i in range(n)] MAX_SIZE = 1000 def msort(a, b): assert len(a) == len(b) if len(a) == 1: return a, b m = len(a) // 2 x, y = msort(a[:m], b[:m]) w, z = msort(a[m:], b[m:]) if len(a) >= MAX_SIZE and len(b) >= MAX_SIZE: return [], [] t0, t1 = merge(x, y, w, z) return t0, t1 def merge(x, y, w, z): # merge with x and z self.ans = max(self.ans, x[-1] + z[-1]) # def f(a, b): # t = [] # i, j = 0, 0 # while i < len(a) and j < len(b): # if a[i] < b[j]: # t.append(a[i]) # i += 1 # else: # t.append(b[j]) # j += 1 # t.extend(a[i:]) # t.extend(b[j:]) # return t # # t0 = f(x, w) # t1 = f(y, z) # return t0, t1 # 直接用sorted比手写还要快 t0 = sorted(x + w) t1 = sorted(y + z) return t0, t1 self.ans = 0 msort(a, b) return self.ans
调整思路之后发现,对于一个点来说,我们其实就想知道在它右边的 max(A[j] - j)在哪里,没有想象的那么复杂需要使用归并排序。
class Solution: def maxScoreSightseeingPair(self, A: List[int]) -> int: n = len(A) b = [A[i] - i for i in range(n)] for i in reversed(range(n - 1)): b[i] = max(b[i], b[i + 1]) ans = 0 p = 0 for i in range(n - 1): p = max(p, A[i] + i) res = p + b[i + 1] ans = max(ans, res) return ans
基本上这就有动态规划的意思了。但是仔细观察的话,发现其实 `b` 这个数组也是不需要的。
在设计上面这个算法的时候,其实我是从遍历 `A[i]+i` 这个角度出发的。但如果我们考虑遍历的是 `A[j]-j` ,而如果我们可以保存过去看到的 `max(A[i]+i)` 的话,那完全不必使用到数组。
class Solution: def maxScoreSightseeingPair(self, A: List[int]) -> int: n = len(A) ans = 0 p = 0 for i in range(1, n): # p always < i res = A[p] + p + A[i] - i ans = max(ans, res) if A[i] + i >= A[p] + p: p = i return ans