Leetcode 第316场周赛题解

Leetcode 第316场周赛题解(C++版)

Problem A - 判断两个事件是否存在冲突

题意
给两个字符串表示时间段,问两个时间段是否有交集
思路
计算两个时间段中的最早开始时间到最晚结束时间之间的差值,并将其和两个时间段的时间跨度之和比较。
事实上,直接比较字符串的大小即可。
代码
方法1:

class Solution {
public:
    bool haveConflict(vector& event1, vector& event2) {
        int all=0;
        //开始的时间
        int sh1=(event1[0][0]-'0')*10+(event1[0][1]-'0'),sh2=(event2[0][0]-'0')*10+(event2[0][1]-'0');
        int sm1=(event1[0][3]-'0')*10+(event1[0][4]-'0'),sm2=(event2[0][3]-'0')*10+(event2[0][4]-'0');
        //结束的时间
        int eh1=(event1[1][0]-'0')*10+(event1[1][1]-'0'),eh2=(event2[1][0]-'0')*10+(event2[1][1]-'0');
        int em1=(event1[1][3]-'0')*10+(event1[1][4]-'0'),em2=(event2[1][3]-'0')*10+(event2[1][4]-'0');
        
        if((sh2sm1)){
            swap(sh1,sh2);
            swap(sm1,sm2);
            swap(eh1,eh2);
            swap(em1,em2);
        }
        long long int t1=(eh1-sh1)*60+(em1-sm1),t2=(eh2-sh2)*60+(em2-sm2);
        long long int t=abs((eh2-sh1)*60+(em2-sm1));
        
        if(t1+t2>=t) return true;
        return false;
    }
};

方法2:

class Solution {
public:
    bool haveConflict(vector& event1, vector& event2) {
        return !(event1[0] > event2[1] || event2[0] > event1[1]);
    }
};

Problem B - 最大公因数等于 K 的子数组数目

题意
给定一个数组和正整数k,统计子数组中元素的最大公因数等于k的子数组数目。

思路

数组长度只有1000,直接 O ( n 2 ) O(n^2) O(n2)做法,双重循环暴力。

代码

#define ll long long
class Solution {
public:
    int subarrayGCD(vector<int>& nums, int k) {
        int ans=0,n=nums.size();
        for(int i=0;i<n;i++){
            int gc=nums[i];
            for(int j=i;j<n;j++){
                gc=__gcd(gc,nums[j]);
                if(gc==k) ans++;
            }
        }
        return ans;
    }
};

Problem C - 使数组相等的最小开销

题意
给定数组 nums 和 cost

你可以执行下面操作任意次:

  • 将 nums 中 任意 元素增加或者减小 1 。
  • 对第 i 个元素执行一次操作的开销是 c o s t i cost_i costi

求使得数组元素全部相等的最小代价

思路

看到这个问题可以想到这个问题的简化版本,就是当cost都是1时,使得数组元素全部相等的最小代价就是将数组元素全部变成中位数。
那么将本问题转化为上面这个基础问题的方法就是**“将cost看作cnt”**。
以第一个数组为例,可以看作:求将数组[1,1,3,3,3,5,2,2,2,…,2]的元素全部变成相等的最小代价(所有元素+1和-1的代价均为1)。
所以我们就把这个问题变成了找中位数的问题,将数组按照nums的升序排列后找中位数即可。

代码

#define ll long long
class Solution {
public:
    ll minCost(vector<int>& nums, vector<int>& cost) {
        int n=nums.size();
        vector<pair<ll,ll> > p;
        ll sum=0;
        for(int i=0;i<n;i++)
            p.push_back(pair<int,int>{nums[i],cost[i]}),sum+=(ll)cost[i];
        sort(p.begin(),p.end());
        ll m=0,idx=0;
        for(int i=0;i<n;i++) {
            m+=p[i].second;
            if(m+m>=sum){
                idx=i;
                break;
            }
        }
        ll ans=0;
        for(int i=0;i<n;i++)
            ans+=abs(nums[i]-p[idx].first)*cost[i];
        return ans;
    }
};

Problem D - 使数组相似的最少操作次数

题意

给定原数组和目标数组,每次操作可以选择两个下标不同的元素,一个+2,一个-2,问把原数组变得与目标数组相似的最小操作次数。
如果两个数组中每个元素出现的频率相等,我们称两个数组是相似的。

思路

注意到,奇数只能变成奇数,偶数只能变成偶数。

分别考虑奇数数组和目标的奇数数组以及偶数数组和目标的偶数数组,一定是维持当前的顺序找目标更优。(否则总距离会更长)

而每一次进行操作都可以同时使得两个数更接近与自身的目标,因此,距离目标的总差值每次会减少 4,所以我们只需要计算总差值除以 4 的结果即可。

代码

class Solution {
public:
    long long makeSimilar(vector<int>& nums, vector<int>& target) {
        sort(nums.begin(),nums.end(),[](int a,int b){
            if(a%2 == b%2) return a<b;
            return a%2 < b%2;
        });
        sort(target.begin(),target.end(),[](int a,int b){
            if(a%2 == b%2) return a<b;
            return a%2 < b%2;
        });
        long long ans=0,n=nums.size();
        for(int i=0;i<n;i++)
            ans+=abs(nums[i]-target[i]);
        return ans/4;
    }
};

你可能感兴趣的:(Leetcode,leetcode,算法,职场和发展)