Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 16a3cc5

Browse files
author
lucifer
committed
feat: #1014
1 parent 3ab443a commit 16a3cc5

File tree

1 file changed

+52
-111
lines changed

1 file changed

+52
-111
lines changed

problems/1014.best-sightseeing-pair.md

Lines changed: 52 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -23,126 +23,67 @@ https://leetcode-cn.com/problems/best-sightseeing-pair/description/
2323

2424
## 思路
2525

26-
这是一个很少见的直接考察`排序`的题目。 其他题目一般都是暗含`排序`,这道题则简单粗暴,直接让你排序。
27-
并且这道题目的难度是`Medium`, 笔者感觉有点不可思议。
28-
29-
我们先来看题目的限制条件,这其实在选择算法的过程中是重要的。 看到这道题的时候,大脑就闪现出了各种排序算法,
30-
这也算是一个复习`排序算法`的机会吧。
31-
32-
题目的限制条件是有两个,第一是元素个数不超过 10k,这个不算大。 另外一个是数组中的每一项范围都是`-50k``50k`(包含左右区间)。
33-
看到这里,基本我就排除了时间复杂度为 O(n^2)的算法。
34-
35-
> 我没有试时间复杂度 O(n^2) 的解法,大家可以试一下,看是不是会 TLE。
36-
37-
剩下的就是基于比较的`nlogn`算法,以及基于特定条件的 O(n)算法。
38-
39-
由于平时很少用到`计数排序`等 O(n)的排序算法,一方面是空间复杂度不是常量,另一方面是其要求数据范围不是很大才行,不然会浪费很多空间。
40-
但是这道题我感觉可以试一下。 在这里,我用了两种方法,一种是`计数排序`,一种是`快速排序`来解决。 大家也可以尝试用别的解法来解决。
41-
42-
### 解法一 - 计数排序
43-
44-
时间复杂度 O(n)空间复杂度 O(m) m 为数组中值的取值范围,在这道题就是`50000 * 2 + 1`
45-
46-
我们只需要准备一个数组取值范围的数字,然后遍历一遍,将每一个元素放到这个数组对应位置就好了,
47-
放的规则是`索引为数字的值,value为出现的次数`
48-
49-
这样一次遍历,我们统计出了所有的数字出现的位置和次数。 我们再来一次遍历,将其输出到即可。
50-
51-
![sort-an-array-1](../assets/problems/912.sort-an-array-1.png)
52-
53-
### 解法二 - 快速排序
54-
55-
快速排序和归并排序都是分支思想来进行排序的算法, 并且二者都非常流行。 快速排序的核心点在于选择轴元素。
56-
57-
每次我们将数组分成两部分,一部分是比 pivot(轴元素)大的,另一部分是不比 pivot 大的。 我们不断重复这个过程,
58-
直到问题的规模缩小的寻常(即只有一个元素的情况)。
59-
60-
快排的核心点在于如何选择轴元素,一般而言,选择轴元素有三种策略:
26+
最简单的思路就是两两组合,找出最大的,妥妥超时,我们来看下代码:
27+
28+
```python
29+
class Solution:
30+
def maxScoreSightseeingPair(self, A: List[int]) -> int:
31+
n = len(A)
32+
res = 0
33+
for i in range(n - 1):
34+
for j in range(i + 1, n):
35+
res = max(res, A[i] + A[j] + i - j)
36+
return res
37+
```
6138

62-
- 数组最左边的元素
63-
- 数组最右边的元素
64-
- 数组中间的元素(我采用的是这种,大家可以尝试下别的)
65-
- 数组随机一项元素
39+
我们思考如何优化。 其实我们可以遍历一遍数组,对于数组的每一项`A[j] - j` 我们都去前面找`最大`的 A[i] + i (这样才能保证结果最大)。
6640

67-
![sort-an-array-2](../assets/problems/912.sort-an-array-2.png)
41+
我们考虑使用动态规划来解决, 我们使用 dp[i] 来表示 数组 A 前 i 项的`A[i] + i`的最大值。
6842

69-
(图片来自: https://www.geeksforgeeks.org/quick-sort/)
43+
```python
44+
class Solution:
45+
def maxScoreSightseeingPair(self, A: List[int]) -> int:
46+
n = len(A)
47+
dp = [float('-inf')] * (n + 1)
48+
res = 0
49+
for i in range(n):
50+
dp[i + 1] = max(dp[i], A[i] + i)
51+
res = max(res, dp[i] + A[i] - i)
52+
return res
53+
```
7054

71-
> 图片中的轴元素是最后面的元素,而提供的解法是中间元素,这点需要注意,但是这并不影响理解
55+
如上其实我们发现,dp[i + 1] 只和 dp[i] 有关,这是一个空间优化的信号。我们其实可以使用一个变量来记录,而不必要使用一个数组,代码见下方
7256

7357
## 关键点解析
7458

75-
- 排序算法
76-
- 注意题目的限制条件从而选择合适的算法
77-
7859
## 代码
7960

80-
计数排序:
81-
82-
代码支持: JavaScript
83-
84-
```js
85-
/**
86-
* @param {number[]} nums
87-
* @return {number[]}
88-
*/
89-
var sortArray = function(nums) {
90-
const counts = Array(50000 * 2 + 1).fill(0);
91-
const res = [];
92-
for (const num of nums) counts[50000 + num] += 1;
93-
for (let i in counts) {
94-
while (counts[i]--) {
95-
res.push(i - 50000);
96-
}
97-
}
98-
return res;
99-
};
61+
```python
62+
class Solution:
63+
def maxScoreSightseeingPair(self, A: List[int]) -> int:
64+
n = len(A)
65+
pre = A[0] + 0
66+
res = 0
67+
for i in range(1, n):
68+
res = max(res, pre + A[i] - i)
69+
pre = max(pre, A[i] + i)
70+
return res
10071
```
10172

102-
快速排序:
103-
104-
代码支持: JavaScript
105-
106-
```js
107-
function swap(nums, a, b) {
108-
const temp = nums[a];
109-
nums[a] = nums[b];
110-
nums[b] = temp;
111-
}
112-
113-
function helper(nums, start, end) {
114-
if (start >= end) return;
115-
const pivotIndex = start + ((end - start) >>> 1);
116-
const pivot = nums[pivotIndex];
117-
let i = start;
118-
let j = end;
119-
while (i <= j) {
120-
while (nums[i] < pivot) i++;
121-
while (nums[j] > pivot) j--;
122-
if (i <= j) {
123-
swap(nums, i, j);
124-
i++;
125-
j--;
126-
}
127-
}
128-
helper(nums, start, j);
129-
helper(nums, i, end);
130-
}
131-
132-
/**
133-
* @param {number[]} nums
134-
* @return {number[]}
135-
*/
136-
var sortArray = function(nums) {
137-
helper(nums, 0, nums.length - 1);
138-
return nums;
139-
};
73+
## 小技巧
74+
75+
Python 的代码如果不使用 max,而是使用 if else 效率目测会更高,大家可以试一下。
76+
77+
```python
78+
class Solution:
79+
def maxScoreSightseeingPair(self, A: List[int]) -> int:
80+
n = len(A)
81+
pre = A[0] + 0
82+
res = 0
83+
for i in range(1, n):
84+
# res = max(res, pre + A[i] - i)
85+
# pre = max(pre, A[i] + i)
86+
res = res if res > pre + A[i] - i else pre + A[i] - i
87+
pre = pre if pre > A[i] + i else A[i] + i
88+
return res
14089
```
141-
142-
## 扩展
143-
144-
- 你是否可以用其他方式排序算法解决
145-
146-
## 参考
147-
148-
- [QuickSort - geeksforgeeks](https://www.geeksforgeeks.org/quick-sort/)

0 commit comments

Comments
 (0)