一、题目描述:
二、思路分析:
这道题看起来很简单,图嘛!
- 先设置二维数组,遍历边!
- 一个边上两个点,在二维数组所有和该点有关系的都加1,(x,y)只加一次1
- 遍历query,for循环二维数组算出超过query——i的个数
死的老惨了
但是其实题是做出来了的,那就需要逐步优化
- 二维数组如果是点对ab,那么每次循环都要对二维数组进行大量更新,我们设置一个一维数组,记录点旁边的边的个数,并将二维数组改为ab相连的边的个数,这么一改,省下了四个for循环
自鸣得意,提交!
还是超时
- 将二维数组改为一维数组,这样一个好处时从
n^2变成了n*(n - 1)/2,我当然知道这个改动不大,但同时也可以对数组使用sort排序,原先的遍历计数改为了遇到比query[i]大的就退出,又省了一步
自鸣得意,提交!
还是超时
- 之前既然想到了sort,也就是出现了有序数组,不如就从遍历改为二分,n变logn! 自鸣得意,提交!
还是超时
我做双周赛时就想到了这些,其实离答案很近了,这也是我看完答案失眠的原因,希望读者做完题再往下看。
三、AC 代码:
class Solution {
public:
vector<int> countPairs(int n, vector<vector<int>>& edges, vector<int>& queries) {
vector<int> deg(n + 1, 0);
int nEdges = edges.size();
unordered_map<int, int> overlap;
vector<vector<int>> distinctEdges; // 去除重边后的边数组,这样处理每个 query 时能少遍历几条边
auto encode = [n](int a, int b) -> int {return max(a, b) * (n + 1) + min(a, b);};
for (int i = 0; i < nEdges; i++) {
int p = edges[i][0], q = edges[i][1];
deg[p]++;
deg[q]++;
int idx = encode(p, q);
if (overlap.find(idx) == overlap.end()) {
distinctEdges.push_back({p, q});
}
overlap[idx]++;
}
vector<int> sortedDeg(deg.begin() + 1, deg.end());
sort(sortedDeg.begin(), sortedDeg.end());
int nQueries = queries.size();
vector<int> ret(nQueries);
for (int i = 0; i < nQueries; i++) {
int l = 0, r = n - 1;
int cnt = 0;
while (l < n) {
while (r > l && sortedDeg[l] + sortedDeg[r] > queries[i]) {
r--;
}
cnt += (n - max(l, r) - 1);
l++;
}
for (int j = 0; j < distinctEdges.size(); j++) {
int p = distinctEdges[j][0], q = distinctEdges[j][1];
int idx = encode(p, q);
if (deg[p] + deg[q] > queries[i] && deg[p] + deg[q] - overlap[idx] <= queries[i]) {
cnt--;
}
}
ret[i] = cnt;
}
return ret;
}
};
四、总结:
这个代码是那个题解的,我按这个代码写其实还是超时,他的优化基本就是把一个枚举点对改为枚举边,前面通过双指针求值。
本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情