本题是第273场周赛的Q3,LC竞赛分为1761。考察的是数学找规律。这题大概是近期最花我时间的题目了,找规律写代码前前后后花了半个小时。
方法一. 哈希+暴力(超时)
用哈希表将相同元素的所有下标存起来,然后暴力遍历算间隔之和,时间复杂度为O(n^2),代码如下:
class Solution {
public:
vector<long long> getDistances(vector<int>& arr) {
unordered_map<int,vector<int>> record;
for(int i=0;i<arr.size();i++){
if(record.find(arr[i])==record.end()){
vector<int> tmp(1,i);
pair<int,vector<int>> a1 = {arr[i],tmp};
record.insert(a1);
}
else
record[arr[i]].push_back(i);
}
vector<long long> res;
for(int i=0;i<arr.size();i++){
long long distance = 0;
for(int i1=0;i1<record[arr[i]].size();i1++){
distance += abs(i - record[arr[i]][i1]);
}
res.push_back(distance);
}
return res;
}
};
方法二. 哈希 + 找规律(时间超过5.56%C++用户)
我们发现了一个规律,设 distance(i,j) 是第 i 个相同元素和第 j 个相同元素之间的距离,设record[i] 是第 i 个相同元素的间隔之和,设该相同元素一共有 n 个, 那么对于任意 i 1,record[i] = record[i-1] + (2*i - n)* distance(i - 1,i)。
规律示意图如下:
把四个等式加起来,规律就一目了然了。通过这个规律,我们只需要暴力计算相同元素之中第一个的间隔之和,这样就可以把距离的计算的复杂度缩减到常数级别,因为要计算O(n)个距离,所以总的距离计算的时间复杂度为O(n)。
我们新增了一个distance_record哈希表,主要是用来存 record[i-1] 以快速计算 record[i] 的,同时,distance_record的size天然地反映了当前相同元素是第几个相同元素,可以利用它简化代码,快速找到当前相同元素的下标。
代码如下:
class Solution {
public:
vector<long long> getDistances(vector<int>& arr) {
unordered_map<int,vector<int>> record;
for(int i=0;i<arr.size();i++){
if(record.find(arr[i])==record.end()){
vector<int> tmp(1,i);
pair<int,vector<int>> a1 = {arr[i],tmp};
record.insert(a1);
}
else
record[arr[i]].push_back(i);
}
vector<long long> res;
unordered_map<int,vector<long long>> distance_record;
for(int i=0;i<arr.size();i++){
long long distance = 0;
int index = i;
if(i == record[arr[i]][0]){
for(int i1=0;i1<record[arr[i]].size();i1++){
distance += abs(i - record[arr[i]][i1]);
}
vector<long long> tmp(1,distance);
pair<int,vector<long long>> a1 = {arr[i],tmp};
distance_record.insert(a1);
}
else{
int n = record[arr[i]].size();
int index1 = distance_record[arr[i]].size();
distance = (2*index1-n)*
(record[arr[i]][index1] - record[arr[i]][index1-1])
+ distance_record[arr[i]][index1-1];
distance_record[arr[i]].push_back(distance);
}
res.push_back(distance);
}
return res;
}
};
我的LC竞赛分是1690+,这段时间一直在刷1650到1800分段的题目,自己思考,慢慢啃,感觉有不少收获,以前Q3都是很随缘的,现在啃多了,就能啃下来了,而且越做越快,不禁感慨付出还是能有回报的。