Leetcode 第316周赛

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

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

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

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

输入:nums = [9,3,1,2,6,3], k = 3
输出:4
解释:nums 的子数组中,以 3 作为最大公因数的子数组如下:
- [9,3,1,2,6,3]
- [9,3,1,2,6,3]
- [9,3,1,2,6,3]
- [9,3,1,2,6,3]

本题主要考察知识点:

(1)最大公因数,可使用algorithm库中的函数__gcd(x,y)。

其中__gcd(x,y)推导,可以使用辗转相除法【即两数相除,取余数重复进行相除,直到余数为0时,前一个除数即为最大公约数】

287=91*3+14    //  287%91   余14  
91=14*6+7      //   91%14   余7
14=7*2         //   14%7    余0  即最后一个除数为最大公因数

inline int gcd(int a,int b){    
    if(a%b==0) 
    return b;        
    else return (gcd(b,a%b));
}

库函数__gcd 同样道理。
class Solution {
public:
int gcd(int a,int b){
    return a%b?gcd(b,a%b):b;
}
    int subarrayGCD(vector<int>& nums, int k) {
        int n=nums.size();
        int res=0;
        for(int i=0;i<n;i++){
            if(nums[i]%k==0){
 //只有子数组的首个元素是k的倍数的元素,才可能存在连续子数组的最大公因数为k
            int x=0;
            for(int j=i;j<n;j++){
                x=gcd(x,nums[j]);//求得元素组的最大公因数是x,判断x是否为k
 //下一个元素代入,判断和前面的子数组元素(最大公因数x)间的最大公因数是多少,如 9 9 3 4 9 3
                if(x==k)//若是,则是一个子数组
                res++;
            }
            }
        }
        return res;
    }
};

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

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

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

  • 将 nums 中 任意 元素增加或者减小 1 。

对第 i 个元素执行一次操作的开销是 cost[i] 。

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

输入:nums = [1,3,5,2], cost = [2,3,1,14]
输出:8
解释:我们可以执行以下操作使所有元素变为 2 :
- 增加第 0 个元素 1 次,开销为 2 。
- 减小第 1 个元素 1 次,开销为 3 。
- 减小第 2 个元素 3 次,开销为 1 + 1 + 1 = 3 。
总开销为 2 + 3 + 3 = 8 。
这是最小开销。

462. 最小操作次数使数组元素相等 II

将nums排序后,各点落入坐标位置如图。若使各点到target位置操作和最小(距离最小),那么target就应该是中位数。从两侧往内侧剖析,nums最小值和最大值到target距离和应是固定值(max-min),那么内侧点皆是如此;假设个数为偶数,落在了最中间,但是不影响target线移动到最内侧的上下某一个点上,个数是奇数的话,则是落在最中间那个点。以上白话实际就是为了说明以下数学问题:差的平方和 Σ(x-t)^2 最小时,t 为平均值;差的绝对值之和 Σ|x-t| 最小时,t 为中位数。

 以上是拓展知识,而该题目则是对每个nums数都附加了权重,实际可以理解为每个nums[i],重复出现了cost[i],这样就和上面的问题大同小异了。

//朴素版本

class Solution {
public:
    long long minCost(vector<int>& nums, vector<int>& cost) {
   vector<pair<int,int>>a;
   long long all=0;
    int n=nums.size();
    for(int i=0;i<n;i++){
        a.push_back(pair<int,int>(nums[i], cost[i]));
        all+=cost[i];
    }
    sort(a.begin(),a.end(),[&](pair<int,int>&a1,pair<int,int>&a2){
        return a1.first<a2.first;
    });
    long long pd=0,mid=all/2;//mid是中位数的位置(数目的一半)
    for(int i=0;i<n;i++){
    pd+=a[i].second;
    if(pd>=mid){
        mid=a[i].first;//mid继续利用,记录中位数
        break;
    }
    }
   //以上动作寻找中位数是nums哪一位
    long long res=0;
    for(auto m:a){
        res+=(long)abs(m.first-mid)*(long)m.second;
    }
return res;

    }
};

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,所以res/4是最终结果。

class Solution {
public:
    long long makeSimilar(vector<int>& nums, vector<int>& target) {
    sort(nums.begin(),nums.end());
    sort(target.begin(),target.end());
    long long res=0;
    int pd[2]={0,0};
    for(auto m:nums){
        int n=m%2;
        //偶数则pd[0]当做下标变化,奇数则pd[1]当做下标变化
        while(n!=target[pd[n]]%2) pd[n]++;//找target中下一个与nums同类型的
        res+=abs(m-target[pd[n]++]);
    }
    return res/4;
    }
};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值