LeetCode刷题——第 280 场周赛

6004. 得到 0 的操作数

题目

给你两个 非负 整数 num1 和 num2 。

每一步 操作 中,如果 num1 >= num2 ,你必须用 num1 减 num2 ;否则,你必须用 num2 减 num1 。

例如,num1 = 5 且 num2 = 4 ,应该用 num1 减 num2 ,因此,得到 num1 = 1 和 num2 = 4 。然而,如果 num1 = 4且 num2 = 5 ,一步操作后,得到 num1 = 4 和 num2 = 1 。
返回使 num1 = 0 或 num2 = 0 的 操作数 。

示例 1:

输入:num1 = 2, num2 = 3
输出:3
解释:

  • 操作 1 :num1 = 2 ,num2 = 3 。由于 num1 < num2 ,num2 减 num1 得到 num1 = 2 ,num2 = 3 - 2 = 1 。
  • 操作 2 :num1 = 2 ,num2 = 1 。由于 num1 > num2 ,num1 减 num2 。
  • 操作 3 :num1 = 1 ,num2 = 1 。由于 num1 == num2 ,num1 减 num2 。 此时 num1 = 0 ,num2 = 1 。由于 num1 == 0 ,不需要再执行任何操作。 所以总操作数是 3 。

示例 2:

输入:num1 = 10, num2 = 10
输出:1
解释:

  • 操作 1 :num1 = 10 ,num2 = 10 。由于 num1 == num2 ,num1 减 num2 得到 num1 = 10 - 10 = 0 。 此时 num1 = 0 ,num2 = 10 。由于 num1 == 0 ,不需要再执行任何操作。
    所以总操作数是 1 。

提示:

0 <= num1, num2 <= 10^5

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/count-operations-to-obtain-zero
分析
按照题目的方式直接进行模拟会超时,所以我们需要对其进行化简。我们假设num1比num2大很多,那么就要进行多次相减,直到减出来的数比num2小为止,最后这个数为最初的num1 % num2,他们直接相减的次数为num1 / num2,我们根据这一特征进行模拟即可。
代码

class Solution {
public:
    int countOperations(int num1, int num2) {
        int cnt=0;
        if(num1 == 0 || num2 == 0){
            return 0;
        }
        if(num1 < num2){
            int tmp = num1;
            num1 = num2;
            num2 = tmp;
        }
        while(num1 % num2){
            cnt += num1 / num2;
            int tmp = num1 % num2;
            num1 = num2;
            num2 = tmp;
        }
        cnt += num1 / num2;
        return cnt;
    }
};

6005. 使数组变成交替数组的最少操作数

题目
给你一个下标从 0 开始的数组 nums ,该数组由 n 个正整数组成。

如果满足下述条件,则数组 nums 是一个 交替数组 :

nums[i - 2] == nums[i] ,其中 2 <= i <= n - 1
nums[i - 1] != nums[i] ,其中 1 <= i <= n - 1
在一步 操作 中,你可以选择下标 i 并将 nums[i] 更改 为 任一 正整数。

返回使数组变成交替数组的 最少操作数 。

示例 1:

输入:nums = [3,1,3,2,4,3]
输出:3 解释: 使数组变成交替数组的方法之一是将该数组转换为 [3,1,3,1,3,1]。
在这种情况下,操作数为 3 。 可以证明,操作数少于 3 的情况下,无法使数组变成交替数组。

示例 2:

输入:nums = [1,2,2,2,2]
输出:2 解释: 使数组变成交替数组的方法之一是将该数组转换为 [1,2,1,2,1].
在这种情况下,操作数为 2 。
注意,数组不能转换成 [2,2,2,2,2] 。因为在这种情况下,nums[0] == nums[1],不满足交替数组的条件。

提示:

1 <= nums.length <= 10^5
1 <= nums[i] <= 10^5

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-operations-to-make-the-array-alternating
分析
根据题目我们可以转换思路为找到最多的不用替换的位置,这样需要修改的位置就达到了最小,我们分别统计奇数位和偶数位数字出现的个数,然后按照最多不被替换的情况计算即可。
代码

class Solution {
public:
    int minimumOperations(vector<int>& nums) {
        vector<int> a, b;
        map<int, int> ma, mb;
        if(nums.size()==1){
            return 0;
        }
        for(int i=0; i < nums.size(); i++){
            if(i % 2 == 0){
                if(ma[nums[i]]==0){
                    a.push_back(nums[i]);
                }
                ma[nums[i]]++;
            }else{
                if(mb[nums[i]]==0){
                    b.push_back(nums[i]);
                }
                mb[nums[i]]++;
            }
        }
        int mxa=0, mxb=0;
        int aa, bb, ans=0;
        for(int i=0; i < a.size(); i++){
            if(mxa < ma[a[i]]){
                mxa = ma[a[i]];
                aa=a[i];
            }
        }
        for(int i=0; i < b.size(); i++){
            if(b[i] != aa && mxb < mb[b[i]]){
                 mxb = mb[b[i]];
            }
        }
        ans = mxa + mxb;
        mxa =0, mxb = 0;
        for(int i=0; i < b.size(); i++){
            if(mxb < mb[b[i]]){
                 mxb = mb[b[i]];
                bb = b[i];
            }
        }
        for(int i=0; i < a.size(); i++){
            if(a[i] != bb && mxa < ma[a[i]]){
                mxa = ma[a[i]];
                aa=a[i];
            }
        }
        ans = max(ans, mxa + mxb);
        return nums.size()-ans;
    }
};

2171. 拿出最少数目的魔法豆

给你一个 正 整数数组 beans ,其中每个整数表示一个袋子里装的魔法豆的数目。

请你从每个袋子中 拿出 一些豆子(也可以 不拿出),使得剩下的 非空 袋子中(即 至少 还有 一颗 魔法豆的袋子)魔法豆的数目 相等 。一旦魔法豆从袋子中取出,你不能将它放到任何其他的袋子中。

请你返回你需要拿出魔法豆的 最少数目。

示例 1:

输入:beans = [4,1,6,5]
输出:4
解释:

  • 我们从有 1 个魔法豆的袋子中拿出 1 颗魔法豆。 剩下袋子中魔法豆的数目为:[4,0,6,5]
  • 然后我们从有 6 个魔法豆的袋子中拿出 2 个魔法豆。 剩下袋子中魔法豆的数目为:[4,0,4,5]
  • 然后我们从有 5 个魔法豆的袋子中拿出 1 个魔法豆。 剩下袋子中魔法豆的数目为:[4,0,4,4] 总共拿出了 1 + 2 + 1 = 4 个魔法豆,剩下非空袋子中魔法豆的数目相等。 没有比取出 4 个魔法豆更少的方案。

示例 2:

输入:beans = [2,10,3,2]
输出:7
解释:

  • 我们从有 2 个魔法豆的其中一个袋子中拿出 2 个魔法豆。 剩下袋子中魔法豆的数目为:[0,10,3,2]
  • 然后我们从另一个有 2 个魔法豆的袋子中拿出 2 个魔法豆。 剩下袋子中魔法豆的数目为:[0,10,3,0]
  • 然后我们从有 3 个魔法豆的袋子中拿出 3 个魔法豆。 剩下袋子中魔法豆的数目为:[0,10,0,0] 总共拿出了 2 + 2 + 3 = 7 个魔法豆,剩下非空袋子中魔法豆的数目相等。 没有比取出 7 个魔法豆更少的方案。

提示:

1 <= beans.length <= 10^5
1 <= beans[i] <= 10^5

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/removing-minimum-number-of-magic-beans
分析
先对beans排序,然后求前缀和,假设我们最终要得到的长度为beans[i]则取出的豆子数是前i-1位置上豆子的和加上i+1后比beans[i]多的豆子数。
代码

class Solution:
    def minimumRemoval(self, beans: List[int]) -> int:
        beans = sorted(beans)
        summ = sum(beans) 
        ans = summ
        length = len(beans)
        for i in range(length):
            ans = min(ans, summ - (length-i) * beans[i])

        return ans

6007. 数组的最大与和

给你一个长度为 n 的整数数组 nums 和一个整数 numSlots ,满足2 * numSlots >= n 。总共有 numSlots 个篮子,编号为 1 到 numSlots 。

你需要把所有 n 个整数分到这些篮子中,且每个篮子 至多 有 2 个整数。一种分配方案的 与和 定义为每个数与它所在篮子编号的 按位与运算 结果之和。

比方说,将数字 [1, 3] 放入篮子 1 中,[4, 6] 放入篮子 2 中,这个方案的与和为 (1 AND 1) + (3 AND 1) + (4 AND 2) + (6 AND 2) = 1 + 1 + 0 + 2 = 4 。
请你返回将 nums 中所有数放入 numSlots 个篮子中的最大与和。

示例 1:

输入:nums = [1,2,3,4,5,6], numSlots = 3
输出:9
解释:一个可行的方案是 [1, 4] 放入篮子 1中,[2, 6] 放入篮子 2 中,[3, 5] 放入篮子 3 中。 最大与和为 (1 AND 1) + (4 AND 1) + (2 AND 2) + (6 AND 2) + (3 AND 3) + (5 AND 3) = 1 + 0 + 2 + 2 + 3 + 1 = 9。

示例 2:

输入:nums = [1,3,10,4,7,1], numSlots = 9
输出:24
解释:一个可行的方案是 [1, 1] 放入篮子 1中,[3] 放入篮子 3 中,[4] 放入篮子 4 中,[7] 放入篮子 7 中,[10] 放入篮子 9 中。 最大与和为 (1 AND1) + (1 AND 1) + (3 AND 3) + (4 AND 4) + (7 AND 7) + (10 AND 9) = 1 +1 + 3 + 4 + 7 + 8 = 24 。 注意,篮子 2 ,5 ,6 和 8 是空的,这是允许的。

提示:

n == nums.length
1 <= numSlots <= 9
1 <= n <= 2 * numSlots
1 <=nums[i] <= 15

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximum-and-sum-of-array
分析
我们可以看到numSlots的值很小,所以我们可以用二进制来表示篮子,但是这个篮子又比较特殊,他可以容纳两个数,所以我们用两个二进制位来表示一个篮子。然后动态规划即可
代码

class Solution {
public:
    int maximumANDSum(vector<int> &nums, int numSlots) {
        int ans = 0;
        vector<int> f(1 << (numSlots * 2));
        for (int i = 0; i < f.size(); ++i) {
            int c = __builtin_popcount(i); //i的二进制中1的位置即放数字的位置,c为二进制1的个数
            if (c >= nums.size()) continue;
            for (int j = 0; j < numSlots * 2; ++j) {
                if ((i & (1 << j)) == 0) { // 枚举空篮子 j
                    int s = i | (1 << j); // s表示在j位置放上数字的情况
                    f[s] = max(f[s], f[i] + ((j / 2 + 1) & nums[c]));
                    ans = max(ans, f[s]);
                }
            }
        }
        return ans;
    }
};
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

艾醒(AiXing-w)

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

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

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

打赏作者

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

抵扣说明:

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

余额充值