2023.2.19LeetCode第333场周赛
A. 合并两个二维数组 - 求和法
思路
使用有序的哈希表来统计
代码
class Solution {
public:
vector<vector<int>> mergeArrays(vector<vector<int>>& nums1, vector<vector<int>>& nums2) {
map<int, int> mp;
for (auto i : nums1) mp[i[0]] += i[1];
for (auto i : nums2) mp[i[0]] += i[1];
vector<vector<int>> a;
for (auto [k, v] : mp) {
a.push_back({k, v});
}
return a;
}
};
B. 将整数减少到零需要的最少操作数
思路
求出所给数的二进制,目标是将所有位变为0
当前位变为0有两种方法
1.直接减去(一次操作)2.先加上本身再减去(两次操作)
假定连续1的数量为n
n为1时,方法1需要一次操作,方法2需要两次操作
n大于1时,方法1需要n次操作,方法2需要两次操作
故n大于1时,使用方法2
代码
class Solution {
public:
int minOperations(int n) {
int ans = 0;
while (n) {
if (n & 1) {
if ((n >> 1) & 1)
n ++ ;
ans ++ ;
}
n >>= 1;
}
return ans;
}
};
C. 无平方子集计数
思路
状态压缩dp
首先找出包含完全平方数作为因子的数,这些数不能被选,应该去掉
由于数最大为30,1-30的质数个数为10,可以用二进制来表示已经有的因子,用状态压缩做
f[i][j]
表示考虑前i个数,已选的因子情况为j时的子集数量
遍历所有数时考虑选与不选当前数,选的时候需要判断条件
代码
class Solution {
public:
int squareFreeSubsets(vector<int>& nums) {
vector<int> a;
vector<int> p = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
int m = p.size();
for (int x : nums) {
bool f = true;
for (int i = 0; i < m; i ++ ) {
if (x % (p[i] * p[i]) == 0) f = false;
}
if (f) a.push_back(x);
}
int n = a.size();
vector<vector<int>> f(n + 1, vector<int>(1 << m));
f[0][0] = 1;
const int mod = 1e9 + 7;
for (int i = 1; i <= n; i ++ ) {
int y = 0;
for (int k = 0; k < m; k ++ )
if (a[i - 1] % p[k] == 0)
y |= (1 << k);
for (int j = 0; j < (1 << m); j ++ ) {
// 不选当前数
f[i][j] = f[i - 1][j];
if ((j | y) == j) {
// 选当前数
f[i][j] = (f[i][j] + f[i - 1][j - y]) % mod;
}
}
}
int ans = 0;
for (int j = 0; j < (1 << m); j ++ )
ans = (ans + f[n][j]) % mod;
ans = (ans - 1 + mod) % mod;
return ans;
}
};