力扣周赛 - 479

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;
    }
};
相关推荐
飞天狗1112 小时前
C. Needle in a Haystack
算法
FMRbpm2 小时前
顺序表实现队列
数据结构·c++·算法·新手入门
飞天狗1112 小时前
G. Mukhammadali and the Smooth Array
数据结构·c++·算法
程序员小远2 小时前
Web自动化测试详解
自动化测试·软件测试·python·selenium·测试工具·职场和发展·测试用例
CQ_YM2 小时前
数据结构之树
数据结构·算法·
某林2122 小时前
SLAM 建图系统配置与启动架构
人工智能·stm32·单片机·嵌入式硬件·算法
不穿格子的程序员2 小时前
从零开始写算法——矩阵类题:图像旋转 + 搜索二维矩阵 II
线性代数·算法·矩阵
罗湖老棍子2 小时前
Knight Moves(信息学奥赛一本通- P1257)
c++·算法·bfs
学学学无无止境3 小时前
力扣-从前序与中序遍历序列构造二叉树
leetcode