Q1 找出数组中的K-or值
-
解题思路:
- 检查0-31位
- 如果对于某一位i,存在至少k个元素该位为1,则将2的i次幂加到答案中
-
解题代码:
class Solution {
public:
int findKOr(vector<int>& nums, int k) {
int ans = 0;
for(int i = 0; i < 31; i++)
{
int cnt = 0;
for(auto num : nums)
{
cnt += (num >> i) & 1;
if(cnt >= k)
{
ans |= (1 << i);
break;
}
}
}
return ans;
}
};
Q2 数组的最小相等和
-
解题思路:
- 首先分别统计两个数组的和,以及其中分别包含多少个0
- 计算数组和 + 0的个数,即分别得到两个数组各自的最小和是多少
- 如果相等,返回该值
- 如果不相等:
- 较小值对应的数组0的个数为0,返回-1
- 返回较大值
-
解题代码:
class Solution {
public:
long long minSum(vector<int>& nums1, vector<int>& nums2) {
long long ans = 0;
long long sum1 = 0, sum2 = 0;
int cnt1 = 0, cnt2 = 0;
for(auto num : nums1)
{
sum1 += num;
cnt1 += num == 0;
}
for(auto num : nums2)
{
sum2 += num;
cnt2 += num == 0;
}
sum1 += cnt1;
sum2 += cnt2;
if(sum1 == sum2)
return sum1;
if(sum1 < sum2 && cnt1 == 0 || sum2 < sum1 && cnt2 == 0)
return -1;
return max(sum1, sum2);
}
};
//调库
class Solution {
public:
long long minSum(vector<int>& nums1, vector<int>& nums2) {
long long ans = 0;
long long sum1 = 0, sum2 = 0;
int cnt1 = 0, cnt2 = 0;
sum1 = accumulate(nums1.begin(), nums1.end(), 0ll);
sum2 = accumulate(nums2.begin(), nums2.end(), 0ll);
cnt1 = count(nums1.begin(), nums1.end(), 0);
cnt2 = count(nums2.begin(), nums2.end(), 0);
sum1 += cnt1;
sum2 += cnt2;
if(sum1 == sum2)
return sum1;
if(sum1 < sum2 && cnt1 == 0 || sum2 < sum1 && cnt2 == 0)
return -1;
return max(sum1, sum2);
}
};
Q3 使数组变美的最小增量运算数
-
解题思路:
- 对于以i位置结尾的子数组,只需考虑i-2、i-1、i三个位置的数中,将哪个数变成大于等于k的数
- 定义dfs(i),表示将[0, i]中的数变成美丽数组需要多少次递增运算
- 状态转移:
- 如果修改i-2位置的数,转移到dfs(i+1) + max(0, k - nums[i-2])
- 如果修改i-1位置的数,转移到dfs(i+2) + max(0, k - nums[i-1]) 为什么是i+2呢,因为dfs(i+1)需要考虑的是i-1, i, i+1位置,而i-1位置已经被修改成了满足大于等于k的数,因此不需要再进行任何修改
- 如果修改i位置的数,转移到dfs(i+3) + max(0, k - nums[i]) 原因同上
- dfs(i) 等于上述三种情况中的最小值
-
解题代码:
class Solution {
public:
long long minIncrementOperations(vector<int>& nums, int k) {
int n = nums.size();
vector<long long> f(n, -1);
function<long long(int)> dfs = [&](int i) -> long long
{
if(i >= n)
return 0;
if(f[i] != -1)
return f[i];
long long &ans = f[i];
ans = LONG_LONG_MAX;
ans = min(ans, dfs(i+1) + max(0, k - nums[i-2]));
ans = min(ans, dfs(i+2) + max(0, k - nums[i-1]));
ans = min(ans, dfs(i+3) + max(0, k - nums[i]));
return ans;
};
return dfs(2);
}
};
-
另一种思路:
-
定义dfs(i, j),表示数组[0, i]位置,且右侧有j个小于k的数时,需要的最小运算数
-
状态转移:
- 选 dfs(i, j) = dfs(i-1, 0) + max(k - nums[i], 0)
- 不选 dfs(i, j) = dfs(i-1, j+1),需要满足 j < 2
- 转移到两者中较小值
-
递归入口:dfs(n-, 0)
-
-
解题代码:
class Solution {
public:
long long minIncrementOperations(vector<int>& nums, int k) {
int n = nums.size();
vector<vector<long long>> f(n, vector<long long>(3, -1));
function<long long(int i, int j)> dfs = [&](int i, int j) -> long long
{
if(i < 0)
return 0;
if(f[i][j] != -1)
return f[i][j];
long long &ans = f[i][j];
ans = dfs(i-1, 0) + max(k - nums[i], 0);
if(j < 2 && nums[i] < k)
ans = min(ans, dfs(i-1, j+1));
return ans;
};
return dfs(n-1, 0);
}
};
- 改递推:
class Solution {
public:
long long minIncrementOperations(vector<int>& nums, int k) {
int n = nums.size();
vector<vector<long long>> f(n+1, vector<long long>(3, 0));
for(int i = 1; i <= n; i++)
{
for(int j = 0; j < 3; j++)
{
f[i][j] = f[i-1][0] + max(k - nums[i-1], 0);
if(j < 2 && nums[i-1] < k)
f[i][j] = min(f[i][j], f[i-1][j+1]);
}
}
return f[n][0];
}
};
- 空间优化
class Solution {
public:
long long minIncrementOperations(vector<int>& nums, int k) {
long long f0 = 0, f1 = 0, f2 = 0;
for(auto num : nums)
{
long long inc = f0 + max(k - num, 0);
f0 = min(inc, f1);
f1 = min(inc, f2);
f2 = inc;
}
return f0;
}
};
Q4 收集所有金币可获得的最大积分
-
解题思路:
-
首先建图
-
定义dfs(i, fa, cnt),表示从fa经过cnt次第二种方法遍历到i节点,遍历以i节点为根节点的字数可以获得的最大积分
-
状态转移:
- 如果在i节点选择用第一种方式,转移到sum(dfs(y, i, cnt)) + coins[i] >> cnt - k,其中y是i的子节点
- 如果在i节点选择用第二种方式,转移到sum(dfs(y, i, cnt+1) + coins[i] >> (cnt+1), 其中y是i的子节点
-
本题要注意的点是,各节点金币数最大为1e4,这意味着当cnt >= 14时,数中所有节点都会变为0,此时最大值只能是0,不用再向下搜索
-
-
解题代码:
class Solution {
public:
int maximumPoints(vector<vector<int>>& edges, vector<int>& coins, int k) {
int n = edges.size() + 1;
vector<vector<int>> g(n);
for(auto &edge : edges)
{
int x = edge[0];
int y = edge[1];
g[x].push_back(y);
g[y].push_back(x);
}
vector<vector<int>> f(n, vector<int>(14, -1));
function<int(int, int, int)> dfs = [&](int i, int fa, int cnt) -> int
{
if(cnt >= 14)
return 0;
if(f[i][cnt] != -1)
return f[i][cnt];
int &ans = f[i][cnt];
int coin = coins[i] >> cnt;
int ans1 = coin - k;
for(auto y : g[i])
{
if(y != fa)
ans1 += dfs(y, i, cnt);
}
int ans2 = coin >> 1;
for(auto y : g[i])
{
if(y != fa)
ans2 += dfs(y, i, cnt+1);
}
ans = max(ans1, ans2);
return ans;
};
return dfs(0, -1, 0);
}
};