Q1 - 3769. 二进制反射排序
🔗 https://leetcode.cn/problems/sort-integers-by-binary-reflection/description/
题目
- 给一个数组,按照其二进制反转之后表达的数字的升序排列后返回
- 若二进制反射值相同,按照原始值的升序排序
- 注意二进制反转之后,忽略前导零
思路
- 用了 C++ 的 bitset,忽略前后导零,计算出二进制反射后的值,进行比较
代码
c++
class Solution {
public:
static int rr(int n) {
std::bitset<32> bs(n);
int ret = 0;
int lower = 0;
for (int i = 0; i < bs.size(); i++) {
if (bs.test(i)) {
lower = i;
break;
}
}
int upper = bs.size() - 1;
for (int i = bs.size() -2; i >= lower; i--) {
if (bs.test(i)) {
upper = i;
break;
}
}
for (int i = lower; i <= upper; i++) {
int tmp = bs.test(i) ? : 0;
ret = ret * 2 + tmp;
}
return ret;
}
static bool cmp(int a, int b) {
int aa = rr(a);
int bb = rr(b);
if (aa == bb) {
return a < b;
}
return aa < bb;
}
vector<int> sortByReflection(vector<int>& nums) {
sort(nums.begin(), nums.end(), cmp);
return nums;
}
};
Q2 - 3770. 可表示为连续质数和的最大质数
🔗 https://leetcode.cn/problems/largest-prime-from-consecutive-prime-sum/description/
题目
- 返回小于等于 n 的最大质数,且该质数可以表示为,由 2 开始的若干连续质数的和
- 若不存在该质数,则返回零
思路
- 若当前数字小于 2,直接返回 0,若大于等于 2,必然存在满足条件的质数,2 是保底答案
- 朴素思路是:筛选小于等于 n 的所有质数,并判断其是否可以用 prime 的 pre_sum 表达。但是按照这样写的思路容易 TLE
- 优化思路:因为要求该质数需要由 2 开始的连续质数和表达,其实并不需要筛选出所有到 n 的质数,而是滚动计算 prime 的 sum,判断 sum 是否为质数,记录这过程中的最大质数,当 sum 超过 n,可以直接结束
代码
c++
class Solution {
public:
bool is_prime(int n) {
int upper = sqrt(n);
for (int i = 2; i <= upper; i++) {
if (n % i == 0)
return false;
}
return true;
}
int largestPrime(int n) {
if (n < 2)
return 0;
if (n == 2)
return 2;
int ret = 2;
bool prime[500000 + 10];
memset(prime, 0, sizeof(prime));
prime[2] = true;
int sum = 2;
int ans = 2;
for (int i = 3; i <= n; i++) {
if (is_prime(i) == false)
continue;
prime[i] = true;
sum += i;
if (sum <= n) {
if (is_prime(sum)) ans = sum;
} else {
break;
}
}
return ans;
}
};
Q3 - 3771. 探索地牢的得分
🔗 https://leetcode.cn/problems/total-score-of-dungeon-runs/description/
题目
- 有初始能量 hp
- 每一个地牢消耗能量 damage[i],若当前剩余能量大于等于 requirement[i],当前地牢得一分。不论当前地牢是否得分,也不论当前剩余的能量多大,都可以去往下一个地牢
- 定义 score(i) 为,从地牢
i出发走到最后一个地牢,可以得到的分数 - 返回 score(1) + score(2) + ... + score(n)
思路
- 注意滑动窗口用在这里会错误,因为无法判断地牢走到哪里后续就不得分了,可能当前地牢不得分,但是后续地牢可能得分
- 若按照题目朴素模拟,根据数据量,会 TLE
- 这里比较秒的一个思路转换是,对每一个地牢 k,可以计算整体可以贡献的分数,或者说次数
- 这个分数的计算,就是找地牢 k 之前,从 j 到 k,hp - (pre_damage[k] - pre_damage[j-1] ≥ requirement[k]
- pre_damage 是单调递增队列,通过 lower_bound 找到大于等于 requirement[k] + pre_damage[k] - hp 对应的 pre_damage[j-1]
- 即从 j 及以后的地牢到 k,都能拿到地牢 k 的分数,k 可以贡献的整体分数是 k - j + 1
代码
c++
class Solution {
public:
long long totalScore(int hp, vector<int>& damage, vector<int>& requirement) {
long long answer = 0;
int n = damage.size();
vector<int> pre_sum;
pre_sum.push_back(0);
for (int i = 0; i < n; i++) {
pre_sum.push_back(pre_sum[i] + damage[i]);
int tmp = requirement[i] + pre_sum[i+1] - hp;
auto it = lower_bound(pre_sum.begin(), pre_sum.end(), tmp);
if (it == pre_sum.end()) continue;
int j = it - pre_sum.begin();
answer += (i - j + 1);
}
return answer;
}
};
Q4 - 3772. 树中子图的最大得分
🔗 https://leetcode.cn/problems/maximum-subgraph-score-in-a-tree/description/
题目
- 给一个树,树中每一个节点,要么是好节点,要么是坏节点
- 对于一个子图,其分数是子图中,所有好节点个数 - 坏节点个数
- 返回一个和节点数对应的数组,第 i 个元素表示,包含节点
i的所有 连通子图 中可能的最大得分
思路
- dfs + bp
- 先以 0 为根节点, 通过 dfs 计算出 max_score[0],具体的 dfs 思路就是
- max_score[0] = good[0] ? 1 : -1 + max(partial_score[child], 0)
- 其中 partial_score[child] 是以 child 为根节点的子树的分数
- 现在有了根节点的 max_score,可以通过状态转移计算出根节点 child 的 max_score:
- partial_score[child] 是以 child 为根节点的子树的分数
- 主要是判断是否包含以 child 为根,root 子树的分数
- 以 child 为根,root 子树的分数,是 max_score[root] 去掉在 root 为根,child 为子树时的分数贡献
- 如果 child 为子树时的分数贡献小于零,那么实际上相当于没有贡献,donate = max(partial_score[child], 0)
- score_f = max_score[root] - donate
- 当然判断是否包含 root 子树,也要看其贡献
- max_score[child] = partial_score[child] + max(0, score_f )
代码
c++
class Solution {
public:
void dfs(int fa, int root, vector<int>& score, int n, vector<vector<int>>& new_edges, vector<int>& good) {
score[root] = good[root] ? 1 : -1;
for (auto child : new_edges[root]) {
if (child == fa) continue;
dfs(root, child, score, n, new_edges, good);
score[root] += max(0, score[child]);
}
}
void dfs2(int fa, int root, vector<int>& ans, vector<int>& score, vector<vector<int>>& new_edges) {
for (auto child : new_edges[root]) {
if (child == fa) continue;
ans[child] = score[child] + max(0, ans[root] - max(score[child], 0));
dfs2(root, child, ans, score, new_edges);
}
}
vector<int> maxSubgraphScore(int n, vector<vector<int>>& edges, vector<int>& good) {
vector<vector<int>> new_edges(n);
for (auto edge : edges) {
int a = edge[0], b = edge[1];
new_edges[a].push_back(b);
new_edges[b].push_back(a);
}
vector<int> score(n);
dfs(-1, 0, score, n, new_edges, good);
vector<int> ans(n);
ans[0] = score[0];
dfs2(-1, 0, ans, score, new_edges);
return ans;
}
};