力扣刷题记录: 2121. 相同元素的间隔之和

        本题是第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 \geq 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都是很随缘的,现在啃多了,就能啃下来了,而且越做越快,不禁感慨付出还是能有回报的。

  • 22
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值