Leetcode-第316场周赛

第 316 场周赛 - 力扣(LeetCode)icon-default.png?t=M85Bhttps://leetcode.cn/contest/weekly-contest-316/

这次周赛只做了两道题,对于困难题的思考还是不太熟练,在看了灵神的视频讲解后,自己梳理了一下思路写出了代码。

6214. 判断两个事件是否存在冲突

题目描述:

给你两个字符串数组 event1 和 event2 ,表示发生在同一天的两个闭区间时间段事件,其中:

event1 = [startTime1, endTime1] 且
event2 = [startTime2, endTime2]
事件的时间为有效的 24 小时制且按 HH:MM 格式给出。

当两个事件存在某个非空的交集时(即,某些时刻是两个事件都包含的),则认为出现 冲突 。

如果两个事件之间存在冲突,返回 true ;否则,返回 false 。

题目解析:

直接通过字符串的比较即可,如果两个事件之间不存在交集的话,那么要么第二个事件的开始时间大于等于第一个事件的结束时间,要么第一个事件的开始时间大于等于第二个时间的结束时间,如果满足这两种情况中的一种就返回false,否则返回true,代码如下:

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

执行用时:4 ms, 在所有 C++ 提交中击败了100.00%的用户

内存消耗:10.7 MB, 在所有 C++ 提交中击败了100.00%的用户


6224. 最大公因数等于K的子数组数目:

题目描述:

给你一个整数数组 nums 和一个整数 k ,请你统计并返回 nums 的子数组中元素的最大公因数等于 k 的子数组数目。

子数组 是数组中一个连续的非空序列。

数组的最大公因数 是能整除数组中所有元素的最大整数。

题目解析:

因为数据范围的原因,暴力计算枚举即可,代码如下:

class Solution {
public:
    int cal(int a , int b){
        int temp = a;
        while(temp!=0){
            temp = a%b;
            a = b;
            b = temp;
        }
        return a;
    }
    int subarrayGCD(vector<int>& nums, int k) {
        int cnt = 0;
        for(int i = 0 ; i<nums.size()-1 ; i++){
            if(nums[i]==k)cnt++;
            int temp = nums[i];
            for(int j = i+1 ; j<nums.size() ; j++){
                temp = cal(temp,nums[j]);
                if(temp==k)cnt++;
            }
        }
        if(nums[nums.size()-1]==k)cnt++;
        return cnt;
    }
};

执行用时:28 ms, 在所有 C++ 提交中击败了100.00%的用户

内存消耗:8.6 MB, 在所有 C++ 提交中击败了100.00%的用户

优化方法:假设一组数为1,2,3,3,6,9,从右往左进行子数组选择对应的最大公因数为1,1,3,3,3,9。可以看到对应的公因数从左到右是非递减的有序数列,我们使用一个数组来记录某个数字及左边数字的公因数数组,并记录对应的序号,对数组进行去重操作,用一个标记位来记录最近一个不满足为K的倍数的数,如果某个数不为K的倍数,那么将记录公因数的数组清空,更新标记位。如果该数组第一个数等于K,则将该数对应的序号减去上一个不满足为K的倍数的数的序号,加在结果上。代码如下:

class Solution {
public:
    int subarrayGCD(vector<int>& nums, int k) {
        vector<pair<int,int>> data;
        int i0 = -1;
        int res = 0;
        for(int i = 0 ; i<nums.size() ; i++){
            if(nums[i]%k){
                data.clear();
                i0 = i;
                continue;
            }
            data.push_back({nums[i],i});
            int j = 0 ; 
            for(auto &p : data){
                p.first = gcd(p.first,nums[i]);
                if(data[j].first==p.first){
                    data[j].second = p.second;
                }
                else{
                    j++;
                    data[j] = p;
                }
            }
            data.erase(data.begin()+j+1,data.end());
            if(data[0].first==k)res += data[0].second-i0;
        }
        return res;
    }
};

执行用时:4 ms, 在所有 C++ 提交中击败了100.00%的用户

内存消耗:8.6 MB, 在所有 C++ 提交中击败了100.00%的用户


2448. 使数组相等的最小开销

题目描述:

给你两个下标从 0 开始的数组 nums 和 cost ,分别包含 n 个 正 整数。

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

将 nums 中 任意 元素增加或者减小 1 。
对第 i 个元素执行一次操作的开销是 cost[i] 。

请你返回使 nums 中所有元素 相等 的 最少 总开销。

题目解析:

根据数字的大小对nums和cost进行排序,这里有一个方法,一个数的cost为x,那么其实就相当于x个这个数的cost为1,只需要将其进行扩展然后查找中位数,因为一组数距离中位数的距离之和是最低的,将这个中位数作为目标数进行答案计算即可,代码如下:

// 中位数 开贪
class Solution {
public:
    long long minCost(vector<int>& nums, vector<int>& cost) {
        long long sumcost = 0;
        int len = nums.size();
        for(int i = 0 ; i<len ; i++){
            sumcost += cost[i];
        }
        vector<pair<int,int>> arr(len);
        for(int i = 0 ; i <len ; i++){
            arr[i] = {nums[i],cost[i]};
        }
        sort(arr.begin() , arr.end() , [](const pair<int,int> &a , const pair<int,int> &b)->bool{
            return a.first<b.first;
        });
        long long temp = 0;
        for(int i = 0; i<len ; i++){
            temp += arr[i].second;
            if(temp>sumcost/2){
                temp = arr[i].first;
                break;
            }
        }
        long long res = 0;
        for(int i = 0 ; i<len ; i++){
            res += abs(temp-arr[i].first)*1LL*arr[i].second;
        }
        return res;
    }
};

执行用时:60 ms, 在所有 C++ 提交中击败了100.00%的用户

内存消耗:38.8 MB, 在所有 C++ 提交中击败了100.00%的用户

还有一种方法就是枚举,但是因为数据量的原因,暴力枚举会导致超时,所以这里用到了类似前缀和的一个思想,还是先进行排序,计算所有数的代价总和sumcost,然后计算以第一个数为目标数的代价和med,如果我要换为以第二个数为目标数,代价和需要变小(sumcost-cost[0])*(nums[1]-nums[0]),代价和变大cost[0]*(nums[1]-nums[0])那么设num[1]-nums[0]=d,这个变化总导致变小了(sumcost-2*cost[0])*d,然后计算res(初始值等于med)和med变小过后的值中的最小值即可,进行遍历计算,代码如下:

// 暴力枚举+前缀和
class Solution {
public:
    long long minCost(vector<int>& nums, vector<int>& cost) {
        int len = nums.size();
        vector<pair<int,int>> arr(len);
        for(int i = 0 ; i<len ; i++){
            arr[i] = {nums[i],cost[i]};
        }
        sort(arr.begin(),arr.end(),[](const pair<int,int> &a , const pair<int,int> &b)->bool{
            return a.first<b.first;
        });
        long long res = 0;
        long long med = 0;
        long long sumcost = 0;
        for(int i = 0 ; i<len ; i++){
            res += (arr[i].first-arr[0].first)*1LL*arr[i].second;
            sumcost += arr[i].second;
        }                                                                            
        med = res;
        for(int i = 1 ; i<len ; i++){
            sumcost -= 2*arr[i-1].second;
            med -= sumcost*(arr[i].first-arr[i-1].first);
            res = min(res , med);
        }
        return res;
    }
};

执行用时:64 ms, 在所有 C++ 提交中击败了100.00%的用户

内存消耗:38.7 MB, 在所有 C++ 提交中击败了100.00%的用户


6217. 是数组相似的最少操作数

题目描述:

给你两个正整数数组 nums 和 target ,两个数组长度相等。

在一次操作中,你可以选择两个 不同 的下标 i 和 j ,其中 0 <= i, j < nums.length ,并且:

令 nums[i] = nums[i] + 2 且
令 nums[j] = nums[j] - 2 。
如果两个数组中每个元素出现的频率相等,我们称两个数组是 相似 的。

请你返回将 nums 变得与 target 相似的最少操作次数。测试数据保证 nums 一定能变得与 target 相似。

题目解析:

这道题目是最可惜的吧,我完全能做,但是被第三题卡住了,我没看第四题我淦,就是先对数组进行排序,然后通过%2对数组进行划分,计算总的距离差值过后除4即可,代码如下:

class Solution {
public:
    long long makeSimilar(vector<int>& nums, vector<int>& target) {
        vector<int> pos = {0,0};
        sort(nums.begin(),nums.end());
        sort(target.begin(),target.end());
        long long res = 0;
        for(int i = 0 ; i<nums.size() ; i++){
            int temp = nums[i]%2;
            int &j = pos[temp];
            while(target[j]%2!=temp)++j;
            res += abs(nums[i]-target[j++]);
        }
        return res/4;
    }
};

执行用时:172 ms, 在所有 C++ 提交中击败了100.00%的用户

内存消耗:76.8 MB, 在所有 C++ 提交中击败了100.00%的用户

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值