Leetcode 第 370 场周赛题解

Leetcode 第 370 场周赛题解

  • [Leetcode 第 370 场周赛题解](#Leetcode 第 370 场周赛题解)

Leetcode 第 370 场周赛题解

题目1:2923. 找到冠军 I

思路

模拟。

另解:如果第 j 列的元素值都是 0,说明没有队伍可以击败它,返回 j。

代码

cpp 复制代码
/*
 * @lc app=leetcode.cn id=2923 lang=cpp
 *
 * [2923] 找到冠军 I
 */

// @lc code=start
class Solution
{
public:
    int findChampion(vector<vector<int>> &grid)
    {
        int n = grid.size();
        vector<int> isChampion(n, true);
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                if (grid[i][j])
                    isChampion[j] = false;
        for (int i = 0; i < n; i++)
            if (isChampion[i])
                return i;
        return -1;
    }
};
// @lc code=end

复杂度分析

时间复杂度:O(n2),其中 n 是二维数组 grid 的长度。

空间复杂度:O(n),其中 n 是二维数组 grid 的长度。

题目2:2924. 找到冠军 II

思路

模拟。

本质上是看是否恰好有 1 个入度为 0 的点。

若只有一个,返回这个点的下标;否则,返回 -1。

代码

cpp 复制代码
/*
 * @lc app=leetcode.cn id=2924 lang=cpp
 *
 * [2924] 找到冠军 II
 */

// @lc code=start
class Solution
{
public:
    int findChampion(int n, vector<vector<int>> &edges)
    {
        vector<int> isChampion(n, true);
        for (const vector<int> &edge : edges)
            isChampion[edge[1]] = false;
        int ans = -1;
        for (int i = 0; i < n; i++)
            if (isChampion[i])
            {
                if (ans != -1)
                    return -1;
                ans = i;
            }
        return ans;
    }
};
// @lc code=end

复杂度分析

时间复杂度:O(n+m),其中 m 是数组 edges 的长度。

空间复杂度:O(n)。

题目3:2925. 在树上执行操作以后得到的最大分数

思路

树形 DP。

正难则反,先把所有 valuesi 加到答案中,然后考虑哪些 valuesi 不能选(撤销,不加入答案)。

设当前节点为 x,计算以 x 为根的子树是健康时,失去的最小分数。那么答案就是 values 的元素和,减去「以 0 为根的子树是健康时,失去的最小分数」。

用「选或不选」分类讨论:

  • 第一种情况:失去 valuesx,也就是不加入答案,那么 x 的所有子孙节点都可以加入答案,失去的最小分数就是 valuesx
  • 第二种情况:valuesx 加入答案,问题变成「以 y 为根的子树是健康时,失去的最小分数」,这里 y 是 x 的儿子。如果有多个儿子,累加失去的最小分数。

这两种情况取最小值。注意第一种情况是不会往下递归的,所以当我们递归到叶子的时候,叶子一定不能加入答案,此时直接返回 valuesx.

代码实现时,为了方便判断 x 是否为叶子节点,可以假设还有一条 0 到 −1 的边,这样不会误把根节点 0 当作叶子。

代码

cpp 复制代码
/*
 * @lc app=leetcode.cn id=2925 lang=cpp
 *
 * [2925] 在树上执行操作以后得到的最大分数
 */

// @lc code=start
class Solution
{
public:
    long long maximumScoreAfterOperations(vector<vector<int>> &edges, vector<int> &values)
    {
        int n = values.size();
        vector<vector<int>> g(n);
        g[0].push_back(-1); // 避免误把根节点当作叶子
        for (vector<int> &edge : edges)
        {
            int x = edge[0], y = edge[1];
            g[x].push_back(y);
            g[y].push_back(x);
        }
        // dfs(x, fa) 计算以 x 为根的子树是健康时,失去的最小分数
        function<long long(int, int)> dfs = [&](int x, int father) -> long long
        {
            if (g[x].size() == 1) // x 是叶子
                return values[x];
            long long loss = 0;
            for (int &y : g[x])
            {
                if (y != father)
                {
                    // 计算以 y 为根的子树是健康时,失去的最小分数
                    loss += dfs(y, x);
                }
            }
            return min((long long)values[x], loss); // 两种情况取最小值
        };
        return accumulate(values.begin(), values.end(), 0LL) - dfs(0, -1);
    }
};
// @lc code=end

复杂度分析

时间复杂度:O(n),其中 n 为数组 values 的长度。

空间复杂度:O(n),其中 n 为数组 values 的长度。

题目4:2926. 平衡子序列的最大和

思路

题解:树状数组优化 DP(Python/Java/C++/Go)

代码

cpp 复制代码
/*
 * @lc app=leetcode.cn id=2926 lang=cpp
 *
 * [2926] 平衡子序列的最大和
 */

// @lc code=start
// 树状数组模板(维护前缀最大值)
class BIT
{
    vector<long long> tree;

public:
    BIT(int n) : tree(n, LLONG_MIN) {}

    void update(int i, long long val)
    {
        while (i < tree.size())
        {
            tree[i] = max(tree[i], val);
            i += i & -i;
        }
    }

    long long pre_max(int i)
    {
        long long res = LLONG_MIN;
        while (i > 0)
        {
            res = max(res, tree[i]);
            i &= i - 1;
        }
        return res;
    }
};

class Solution
{
public:
    long long maxBalancedSubsequenceSum(vector<int> &nums)
    {
        int n = nums.size();
        // 离散化 nums[i]-i
        auto b = nums;
        for (int i = 0; i < n; i++)
        {
            b[i] -= i;
        }
        sort(b.begin(), b.end());
        b.erase(unique(b.begin(), b.end()), b.end()); // 去重

        BIT t = BIT(b.size() + 1);
        for (int i = 0; i < n; i++)
        {
            // j 为 nums[i]-i 离散化后的值(从 1 开始)
            int j = lower_bound(b.begin(), b.end(), nums[i] - i) - b.begin() + 1;
            long long f = max(t.pre_max(j), 0LL) + nums[i];
            t.update(j, f);
        }
        return t.pre_max(b.size());
    }
};
// @lc code=end

复杂度分析

时间复杂度:O(nlogn),其中 n 为 nums 的长度。

空间复杂度:O(n),其中 n 为 nums 的长度。

相关推荐
随意起个昵称5 小时前
区间dp-基础题目1(石子合并)
算法·动态规划
吞下星星的少年·-·5 小时前
线段树模板
算法
wunaiqiezixin5 小时前
如何在C++中创建和管理线程
c++
段一凡-华北理工大学5 小时前
2026 高炉炼铁智能化技术全景与演进路径~系列文章11:演进路径与行业未来
大数据·网络·人工智能·算法·工业智能体·高炉炼铁智能化
雪度娃娃6 小时前
转向现代C++——在意为改写的函数添加 override
开发语言·c++
王老师青少年编程6 小时前
csp信奥赛C++高频考点专项训练之前缀和&差分 --【一维差分】:[NOIP 2018 提高组] 铺设道路
c++·前缀和·差分·csp·高频考点·信奥赛·铺设道路
叶小鸡6 小时前
小鸡玩算法-力扣HOT100-多维动态规划
算法·leetcode·动态规划
星马梦缘6 小时前
aaaaa
数据结构·c++·算法
菜菜的顾清寒7 小时前
力扣HOT100(42)链表-随机链表的复制
算法·leetcode·链表
lqqjuly7 小时前
模型剪枝与稀疏化:理论、算法与可运行实现
人工智能·算法·剪枝