Q1 统计移除递增子数组的数目I
- 题目链接
- 解题思路:
- Q3的简单版本
- 解题思路同Q3
Q2 找到最大周长的多边形
-
解题思路:
- 先排序
- 计算前缀和
- 对于每一个ai,在其前面的所有元素的和最大值就是[a0, ai-1]所有元素的和,如果该和大于ai,则可以得到一个由[a0, ai]组成的多边形,更新周长
-
解题代码:
class Solution {
public:
long long largestPerimeter(vector<int>& nums) {
sort(nums.begin(), nums.end());
int n = nums.size();
vector<long long> s(n+1, 0);
for (int i = 1; i <= n; i++) {
s[i] = s[i-1] + nums[i-1];
}
long long ans = -1;
for (int i = 2; i < n; i++) {
if (s[i] > nums[i]) {
ans = max(ans, s[i] + nums[i]);
}
}
return ans;
}
};
Q3 统计移除递增子数组的数目II
-
解题思路:
- 先找后缀最早从哪里开始严格递增
- 枚举开始删除位置i:
- 二分找到严格递增后缀中,第一个严格大于ai-1的位置idx,以i为开始删除位置的删除方案数为n-idx+1
- 枚举到产生第一个不满足前缀严格递增的位置为止
-
解题代码:
class Solution {
public:
long long incremovableSubarrayCount(vector<int>& nums) {
int n = nums.size();
int start = n-1;
for (int i = n-2; i >= 0; i--) {
if (nums[i] >= nums[i+1]) {
break;
}
start -= 1;
}
long long ans = 0;
// start 是后缀最早开始递增的位置
for (int i = 0; i < n; i++) {
int pre = i == 0 ? -1 : nums[i-1];
int l = start, r = n-1;
while (l <= r) {
int m = l + (r - l) / 2;
if (nums[m] > pre) {
r = m - 1;
} else {
l = m + 1;
}
}
ans += (n - l + 1);
if (l == i) {
ans -= 1;
}
if (i != 0 && nums[i] <= nums[i-1]) {
break;
}
}
return ans;
}
};
Q4 树中每个节点放置的金币数目
-
解题思路:
- 在dfs的过程中,保存每个子树中最大的三个以及最小的两个结点的cost,对应开销乘积最大值的两种情况:
- 最大值1 * 最大值2 * 最大值3,三个数均为正数
- 最大值1 * 最小值1 * 最小值2,最大值为正数,两个最小值均为负数
- 维护子树信息时可以用归并排序
- 在dfs的过程中,保存每个子树中最大的三个以及最小的两个结点的cost,对应开销乘积最大值的两种情况:
-
解题代码:
class Solution {
public:
vector<long long> placedCoins(vector<vector<int>>& edges, vector<int>& cost) {
int n = cost.size();
vector<long long> ans(n);
vector<vector<int>> g(n);
for (auto &edge : edges) {
int x = edge[0];
int y = edge[1];
g[x].push_back(y);
g[y].push_back(x);
}
auto unite = [](vector<long long>& a, vector<long long>& b) {
vector<long long> temp(6);
int idx1 = 0, idx2 = 0;
int idx = 0;
while (idx < 3) {
if (a[idx1] > b[idx2]) {
temp[idx++] = a[idx1++];
} else {
temp[idx++] = b[idx2++];
}
}
idx1 = idx2 = 3;
while (idx < 5) {
if (a[idx1] < b[idx2]) {
temp[idx++] = a[idx1++];
} else {
temp[idx++] = b[idx2++];
}
}
temp[5] = a.back() + b.back();
a = move(temp);
};
function<vector<long long>(int, int)> dfs = [&](int x, int fa) -> vector<long long> {
vector<long long> costs = {INT_MIN, INT_MIN, INT_MIN, INT_MAX, INT_MAX, 0}; // 最大的三个数 + 最小的两个数
for (auto y : g[x]) {
if (y == fa) {
continue;
}
auto children = dfs(y, x);
// 更新costs
unite(costs, children);
}
vector<long long> new_node = {cost[x], INT_MIN, INT_MIN, cost[x], INT_MAX, 1};
unite(costs, new_node);
if (costs.back() < 3) {
ans[x] = 1;
return costs;
}
long long temp1 = INT_MIN, temp2 = INT_MIN;
if (costs[0] > INT_MIN && costs[1] > INT_MIN && costs[2] > INT_MIN) {
temp1 = costs[0] * costs[1] * costs[2];
}
if (costs[0] > INT_MIN && costs[3] < INT_MAX && costs[4] < INT_MAX) {
temp2 = costs[0] * costs[3] * costs[4];
}
long long temp = max(temp1, temp2);
if (temp == INT_MIN) {
ans[x] = 1;
} else if (temp < 0) {
ans[x] = 0;
} else {
ans[x] = temp;
}
return costs;
};
dfs(0, -1);
return ans;
}
};