力扣:5965. 相同元素的间隔之和——前缀和

题目:

给你一个下标从 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;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奋斗吧!骚年!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值