# Leetcode 第240场周赛题解
# Problem A - 人口最多的年份 (opens new window)
本题是存活人数 (opens new window)的数据弱化版本。
# 方法一:暴力
本题数据范围很小,可以暴力求解。对于每一个人,逐年遍历计数;最后求出最大值。
- 时间复杂度。
- 空间复杂度。
参考代码(Python 3)
class Solution:
def maximumPopulation(self, logs: List[List[int]]) -> int:
cnt = [0] * 2051
for b, d in logs:
for j in range(b, d):
cnt[j] += 1
hi = 1950
for i in range(1950, 2050):
if cnt[i] > cnt[hi]:
hi = i
return hi
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 方法二:差分数组
更优的做法是使用差分数组。
- 时间复杂度。
- 空间复杂度为。
参考代码(C++)
class Solution {
public:
int maximumPopulation(vector<vector<int>>& logs) {
vector<int> cnt(101);
for (auto &log : logs)
cnt[log[0] - 1950]++, cnt[log[1] - 1950]--;
int hi = 0;
for (int i = 1; i < 101; ++i) {
cnt[i] += cnt[i - 1];
if (cnt[i] > cnt[hi])
hi = i;
}
return hi + 1950;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Problem B - 下标对中的最大距离 (opens new window)
# 方法一:双指针
利用两个数组均为非递增数组的条件,双指针求解。
- 时间复杂度。
- 不考虑两个输入数组,空间复杂度。
参考代码(C++)
class Solution {
public:
int maxDistance(vector<int>& nums1, vector<int>& nums2) {
int n = nums1.size(), m = nums2.size();
int ans = 0;
int ptr = -1;
for (int i = 0; i < n; ++i) {
while (ptr + 1 < m && nums1[i] <= nums2[ptr + 1])
ptr++;
ans = max(ans, ptr - i);
}
return ans;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# Problem C - 子数组最小乘积的最大值 (opens new window)
# 方法一:前缀和+单调栈
经典单调栈题目。因为数组元素都为正数,所以子数组最小值的元素位置一定时,子数组长度越大,得到的乘积越大。
我们利用单调栈可以求出每个元素作为最小值时的最长子数组,再利用预计算的前缀和求得乘积。最后取所有乘积的最大值即可。
- 时间复杂度。
- 空间复杂度。
参考代码(C++)
using ll = long long;
const ll MOD = 1e9 + 7;
class Solution {
public:
int maxSumMinProduct(vector<int>& nums) {
int n = nums.size();
vector<ll> s(n + 1);
for (int i = 1; i <= n; ++i)
s[i] = s[i - 1] + nums[i - 1];
vector<int> l(n, 0), r(n, n - 1);
stack<int> st;
for (int i = 0; i < n; ++i) {
while (!st.empty() && nums[st.top()] > nums[i]) {
r[st.top()] = i - 1;
st.pop();
}
st.push(i);
}
st = stack<int>();
for (int i = n - 1; i >= 0; --i) {
while (!st.empty() && nums[st.top()] > nums[i]) {
l[st.top()] = i + 1;
st.pop();
}
st.push(i);
}
ll ans = 0;
for (int i = 0; i < n; ++i)
ans = max(ans, (s[r[i] + 1] - s[l[i]]) * nums[i]);
return ans % MOD;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# Problem D - 有向图中最大颜色值 (opens new window)
# 方法一:拓扑排序+DAG上动态规划
首先利用拓扑排序判断是否有环,同时可以得到拓扑序列。
按照拓扑序列反向进行动态规划即可。
在动态规划时,我们可以每次只考虑一种字母。每个字母出现次数最大值的最大值即为我们需要的答案。
- 时间复杂度。
- 空间复杂度。
参考代码(C++)
class Solution {
public:
int largestPathValue(string colors, vector<vector<int>>& edges) {
int n = colors.size();
vector<int> deg(n);
vector<vector<int>> adj(n);
for (auto &edge : edges) {
int u = edge[0], v = edge[1];
deg[v]++;
adj[u].emplace_back(v);
}
queue<int> q;
for (int i = 0; i < n; ++i) {
if (deg[i] == 0)
q.push(i);
}
vector<int> topo;
while (!q.empty()) {
int u = q.front();
q.pop();
topo.emplace_back(u);
for (int v : adj[u]) {
deg[v]--;
if (deg[v] == 0)
q.push(v);
}
}
if (topo.size() != n)
return -1;
int ans = 0;
for (int color = 0; color < 26; ++color) {
vector<int> dp(n);
for (int i = n - 1; i >= 0; --i) {
int u = topo[i];
for (int v : adj[u])
dp[u] = max(dp[u], dp[v]);
if (colors[u] - 'a' == color)
dp[u]++;
ans = max(ans, dp[u]);
}
}
return ans;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49