题目:
给你一个下标从 0 开始、由 n 个整数组成的数组 arr 。
arr 中两个元素的 间隔 定义为它们下标之间的 绝对差 。更正式地,arr[i] 和 arr[j] 之间的间隔是 |i - j| 。
返回一个长度为 n 的数组 intervals ,其中 intervals[i] 是 arr[i] 和 arr 中每个相同元素(与 arr[i] 的值相同)的 间隔之和 。
注意:|x| 是 x 的绝对值。
示例 1:
输入:arr = [2,1,3,1,2,3,3]
输出:[4,2,7,2,4,4,5]
解释:
下标 0 :另一个 2 在下标 4 ,|0 - 4| = 4
下标 1 :另一个 1 在下标 3 ,|1 - 3| = 2
下标 2 :另两个 3 在下标 5 和 6 ,|2 - 5| + |2 - 6| = 7
下标 3 :另一个 1 在下标 1 ,|3 - 1| = 2
下标 4 :另一个 2 在下标 0 ,|4 - 0| = 4
下标 5 :另两个 3 在下标 2 和 6 ,|5 - 2| + |5 - 6| = 4
下标 6 :另两个 3 在下标 2 和 5 ,|6 - 2| + |6 - 5| = 5
示例 2:
输入:arr = [10,5,10,10]
输出:[5,0,3,4]
解释:
下标 0 :另两个 10 在下标 2 和 3 ,|0 - 2| + |0 - 3| = 5
下标 1 :只有这一个 5 在数组中,所以到相同元素的间隔之和是 0
下标 2 :另两个 10 在下标 0 和 3 ,|2 - 0| + |2 - 3| = 3
下标 3 :另两个 10 在下标 0 和 2 ,|3 - 0| + |3 - 2| = 4
经历:这道题经历多次迭代做出来了,前两次都是超时
第一次思路:心想这还不简单,两个for循环遍历(一前一后),当数字相等时就将算出距离加入对应的答案数组。代码也少,不出意外超时了!
class Solution {
public:
vector<long long> getDistances(vector<int>& arr) {
int size=arr.size();
vector<long long>res(size);
for(int i=0;i<size-1;i++){
for(int j=i+1;j<size;j++){
if(arr[i]==arr[j]){//当数字相等
int mid=j-i;
res[i]+=mid;
res[j]+=mid;
}
}
}
return res;
}
};
第二次思路:显然上一次有很多重复没有必要的计算。然后可以使用map容器将相同的数字的下标放在一个vector容器中,当遇到相同的数字就将到当前的所有的数字距离进行更新,这样下来就相当于将相同的数字单独拿出来进行计算,没有多余的计算,本以为能过但是还是超时!因为相同数字之间距离计算也可以简化,那就是前缀和。
class Solution {
public:
vector<long long> getDistances(vector<int>& arr) {
int size=arr.size();
vector<long long>res(size);
map<int,vector<int>> map_n;//将相同的值装入map中
for(int i=0;i<size;i++){
int m_size=map_n[arr[i]].size();
if(m_size!=0){
for(int j=0;j<m_size;j++){
int mid=i-map_n[arr[i]][j];
res[i]+=mid;
res[map_n[arr[i]][j]]+=mid;
}
}
map_n[arr[i]].push_back(i);
}
return res;
}
};
第三次:当然这次是看了大佬们的题解,自己前缀和做得比较少,所有没有往这方面想。
具体思路:前缀和可以通过:prenum[i] = 前一个与arr[i]相同的值对应的prenum[pro] + 前一个到当前这个的距离 × 个数。(可以自己画图理解)
那么这个数字的距离其实就是数字前的前缀和与数字后面的后缀和相加,这样我们就可以求出前缀和与后缀和进行相加即可。
class Solution {
public:
vector<long long> getDistances(vector<int>& arr) {
int size=arr.size();
vector<long long>res(size);
map<int,vector<int>> map_n;
map<int,long long> prenum;//前缀和
map<int,long long> nxtnum;//后缀和
for(int i=0;i<size;i++){//将元素加入map中分类
map_n[arr[i]].push_back(i);
}
//对每个相同的元素进行前缀和与后缀和
for(auto it=map_n.begin();it!=map_n.end();it++){
auto &v=it->second;
int v_size=v.size();
prenum[v[0]]=0;
for(int i=1;i<v_size;i++){
prenum[v[i]]=prenum[v[i-1]]+i*(v[i]-v[i-1]);
}
nxtnum[v[v_size-1]]=0;
for(int i=v_size-2;i>=0;i--){
nxtnum[v[i]]=nxtnum[v[i+1]]+(v_size-1-i)*(v[i+1]-v[i]);
}
}
//得出结果
for(int i=0;i<size;i++){
res[i]+=prenum[i];
res[i]+=nxtnum[i];
}
return res;
}
};