力扣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]; } };