LeetCode --- 407周赛

题目列表

3226. 使两个整数相等的位更改次数

3227. 字符串元音游戏

3228. 将 1 移动到末尾的最大操作次数

3229. 使数组等于目标数组所需的最少操作次数

一、使两个整数相等的位更改次数

这题就是看n的二进制位上的1是否包含k的二进制位上的1,即(n&k)==k是否为真,如果为真,则能实现,返回多余的1的个数即可,如果为假,返回-1,代码如下

class Solution {
public:
    int minChanges(int n, int k) {
        return (n&k)==k ? __builtin_popcount(n-k) : -1;
    }
};

二、字符串元音游戏

这题是个脑经急转弯,我们先统计给定字符串中的元音字母出现的次数,然后如果没有思路,我们可以先举几个例子来找找规律。

设 cnt 表示 元音字母出现的次数

  • 当 cnt = 0 时,小红无法操作,小明赢
  • 当 cnt = 1 时,小红移除1个,小明无法操作,小红赢
  • 当 cnt = 2 时,小红移除1个,小明无法操作,小红赢
  • 当 cnt = 3 时,小红移除3个,小明无法操作,小红赢
  • 当 cnt = 4 时,小红移除3个,小明无法操作,小红赢
  • ......

我们不难发现规律,只有当cnt=0时小明才能赢,否则都是小红赢,因为当cnt>=1时,如果cnt为奇数,小红直接全部移除,小明无法操作,如果cnt为偶数,小红移除cnt - 1个,剩余 1 个,小明依旧无法操作,所以小红赢

代码如下

class Solution {
    const string t = "aeiou";
public:
    bool doesAliceWin(string s) {
        for(auto e:s) 
            if(t.find(e)!=string::npos)
                return true;
        return false;
    }
};

三、将1移动到末尾的最大操作次数

这题用贪心,显然我们从前往后依次移动1,这样得到的操作次数最大,也就是让1移动的距离尽可能的短,从而让1移动的次数更多,已知每个1会一直向右移动到头或者移动到下一个1,所以优先移动左边的1,让右边的1不动,会得到最优解。代码如下

class Solution {
public:
    int maxOperations(string s) {
        int n = s.size();
        int i = 0, cnt = 0, ans = 0;
        while(i < n){
            while(i < n && s[i] == '0') i++;
            ans += cnt;
            while(i < n && s[i] == '1') cnt++, i++;
        }
        return ans;
    }
};

四、使数组等于目标数组所需的最小操作次数

这题主要考察对差分数组的理解,看到题目中有对子数组进行+1/-1操作,就要想到差分数组,它能帮助我们在O(1)的事件内完成对数组中一段连续区间的加减操作。

那么这题如何用差分数组来做呢?

首先我们要先算出每个元素和目标元素的差值,即 nums 和 target 的差值,记为 数组 a,然后通过对区间的+1/-1操作,让数组 a 的元素全为 0,并且操作次数要求最少。

这里先说明一点:数组 a 的元素全为 0 <=> 数组 a 的差分数组的元素全为 0,因为数组 a 和数组 a 的差分数组是可以相互推导出来的。所以 问题就从 通过区间操作让数组 a 的元素变为 0 转换成了 通过+1/-1操作让数组 a 的差分数组的元素变为 0,记差分数组为 diff

显然,问题被简化了,这也就是我们使用差分数组来解题的原因

那么怎样才能让操作次数最少呢?举个例子大家就明白了

为啥上面做法得到的操作数最少呢?因为我们尽可能多的使用了免费的操作次数,本质是一种贪心

代码如下

class Solution {
public:
    long long minimumOperations(vector<int>& nums, vector<int>& target) {
        int n = nums.size();
        long long diff[n];
        diff[0] = nums[0] - target[0];
        for(int i = 1; i < n; i++)
            diff[i] = (nums[i] - target[i]) - (nums[i-1] - target[i-1]);
        long long ans = 0, cnt = 0; // cnt 记录可以免费进行的操作
        for(auto x:diff){
            if(x == 0) continue;
            int tmp = cnt + x;
            if(x > 0 && cnt < 0){
                x -= min(x, -cnt);
            }else if(x < 0 && cnt > 0){
                x += min(-x, cnt);
            }
            ans += abs(x);
            cnt = tmp;
        }
        return ans;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值