第 218 场力扣周赛

1.设计 Goal 解析器

请你设计一个可以解释字符串 command 的 Goal 解析器 。command 由 “G”、"()" 和/或 “(al)” 按某种顺序组成。Goal 解析器会将 “G” 解释为字符串 “G”、"()" 解释为字符串 “o” ,"(al)" 解释为字符串 “al” 。然后,按原顺序将经解释得到的字符串连接成一个字符串。

给你字符串 command ,返回 Goal 解析器 对 command 的解释结果。

示例1:
输入:command = “G()(al)”
输出:“Goal”
解释:Goal 解析器解释命令的步骤如下所示:
G -> G
() -> o
(al) -> al
最后连接得到的结果是 “Goal”

示例2:
输入:command = “G()()()()(al)”
输出:“Gooooal”

示例3:
输入:command = “(al)G(al)()()G”
输出:“alGalooG”

class Solution {
public:
    string interpret(string command) {
        string res;
        for(int i=0;i<command.size();i++){
            if(command[i]=='G') res+="G";
            else{
                if(command[i+1]==')'){
                    res+="o";
                    i++;
                }
                else{
                    res+="al";
                    i+=3;
                }
            }
        }
        return res;
    }
};

2.K 和数对的最大数目
给你一个整数数组 nums 和一个整数 k 。
每一步操作中,你需要从数组中选出和为 k 的两个整数,并将它们移出数组。
返回你可以对数组执行的最大操作数。

示例1:
输入:nums = [1,2,3,4], k = 5
输出:2
解释:开始时 nums = [1,2,3,4]:

  • 移出 1 和 4 ,之后 nums = [2,3]
  • 移出 2 和 3 ,之后 nums = []
    不再有和为 5 的数对,因此最多执行 2 次操作。

示例2:
输入:nums = [3,1,3,4,3], k = 6
输出:1
解释:开始时 nums = [3,1,3,4,3]:
移出前两个 3 ,之后nums = [1,4,3]
不再有和为 6 的数对,因此最多执行 1 次操作。

提示:

  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 109
  • 1 <= k <= 109
class Solution {
public:
    int maxOperations(vector<int>& nums, int k) {
        sort(nums.begin(),nums.end());
        int res=0;
        int i=0,j=nums.size()-1;
        while(i<j){
            if(nums[i]+nums[j]==k){
                res++;
                i++;
                j--;
            }
            else if(nums[i]+nums[j]<k){
                i++;
            }
            else    j--;
        }
        return res;
    }

3.连接连续二进制数字
给你一个整数 n ,请你将 1 到 n 的二进制表示连接起来,并返回连接结果对应的 十进制 数字对 1e9 + 7 取余的结果。

示例1:
输入:n = 1
输出:1
解释:二进制的 “1” 对应着十进制的 1 。

示例2:
输入:n = 3
输出:27
解释:二进制下,1,2 和 3 分别对应 “1” ,“10” 和 “11” 。
将它们依次连接,我们得到 “11011” ,对应着十进制的 27 。

示例3:
输入:n = 12
输出:505379714
解释:连接结果为 “1101110010111011110001001101010111100” 。
对应的十进制数字为 118505380540 。
对 1e9 + 7 取余后,结果为 505379714 。

提示:

  • 1 <= n <= 1e5
    这道题其实可以简单理解为这样:假设N=3,那么最后应该输出的结果是11011,如果n=2,那么结果应该是110,如果n=1,那就结果就是1.
    不难发现如果我们要计算3,那么我们从1开始计算,1和2的连接中,1向左移动了2位,那么我们可以直接1<<2+2;这样就可以成功把1和2的二进制连接起来了。接下来连接3,3的二进制是11,有两位,说明我们上一步计算的将结果要左移两位再加上3.
    最后可以总结出我们所需的结果是上一次结果<<这一次需要加上的数字的二进制位数+这次计算的数字值。即tmp=tmp<<i的位数+i;
class Solution {
public:
    int concatenatedBinary(int n) {
        int res=0;
        long long int tmp=0;
        for(int i=1;i<=n;i++){
            int move=0;    //统计需要移动的位数
            int cns=i;
            while(cns){
                move++;
                cns/=2;
            }
            tmp=tmp<<move;
            tmp+=i;
            tmp%=(int)(1E9+7);
        }
        return tmp;
    }
};

4.最小不兼容性
给你一个整数数组 nums​​​ 和一个整数 k 。你需要将这个数组划分到 k 个相同大小的子集中,使得同一个子集里面没有两个相同的元素。
一个子集的 不兼容性 是该子集里面最大值和最小值的差。
请你返回将数组分成 k 个子集后,各子集 不兼容性 的 和 的 最小值 ,如果无法分成分成 k 个子集,返回 -1 。
子集的定义是数组中一些数字的集合,对数字顺序没有要求。

示例1:
输入:nums = [1,2,1,4], k = 2
输出:4
解释:最优的分配是 [1,2] 和 [1,4] 。
不兼容性和为 (2-1) + (4-1) = 4 。
注意到 [1,1] 和 [2,4] 可以得到更小的和,但是第一个集合有 2 个相同的元素,所以不可行。

示例2:
输入:nums = [6,3,8,1,3,1,2,2], k = 4
输出:6
解释:最优的子集分配为 [1,2],[2,3],[6,8] 和 [1,3] 。
不兼容性和为 (2-1) + (3-2) + (8-6) + (3-1) = 6 。

示例3:
输入:nums = [5,3,3,6,3,3], k = 3
输出:-1
解释:没办法将这些数字分配到 3 个子集且满足每个子集里没有相同数字。

提示:

  • 1 <= k <= nums.length <= 16
  • nums.length 能被 k 整除。
  • 1 <= nums[i] <= nums.length
    下面代码是第一名大佬的代码,我没有做出这道题目,暂时先复制下来他的代码,过一段时间再好好研究研究。
class Solution {
private:
    int freq[20];
public:
    int minimumIncompatibility(vector<int>& nums, int k) {
        int n = nums.size();
        vector<int> valid(1 << n, -1);
        for (int mask = 0; mask < (1 << n); ++mask) {
            if (__builtin_popcount(mask) == n / k) {
                for (int j = 0; j < n; ++j) {
                    if (mask & (1 << j)) {
                        ++freq[nums[j]];
                    }
                }
                bool flag = true;
                for (int j = 1; j <= n; ++j) {
                    if (freq[j] > 1) {
                        flag = false;
                        break;
                    }
                }
                if (flag) {
                    int lb = INT_MAX, rb = INT_MIN;
                    for (int j = 1; j <= n; ++j) {
                        if (freq[j] > 0) {
                            lb = min(lb, j);
                            rb = max(rb, j);
                        }
                    }
                    valid[mask] = rb - lb;
                }
                for (int j = 0; j < n; ++j) {
                    if (mask & (1 << j)) {
                        --freq[nums[j]];
                    }
                }
            }
        }
        
        vector<int> f(1 << n, -1);
        f[0] = 0;
        for (int mask = 1; mask < (1 << n); ++mask) {
            if (__builtin_popcount(mask) % (n / k) == 0) {
                for (int sub = mask; sub; sub = (sub - 1) & mask) {
                    if (valid[sub] != -1 && f[mask ^ sub] != -1) {
                        if (f[mask] == -1) {
                            f[mask] = f[mask ^ sub] + valid[sub];
                        }
                        else {
                            f[mask] = min(f[mask], f[mask ^ sub] + valid[sub]);
                        }
                    }
                }
            }
        }
            
        return f[(1 << n) - 1];
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值