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。

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

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

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

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

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

代码实现时,为了方便判断 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 的长度。

相关推荐
许愿与你永世安宁11 分钟前
力扣343 整数拆分
数据结构·算法·leetcode
爱coding的橙子14 分钟前
每日算法刷题Day42 7.5:leetcode前缀和3道题,用时2h
算法·leetcode·职场和发展
ruanjiananquan9917 分钟前
c,c++语言的栈内存、堆内存及任意读写内存
java·c语言·c++
满分观察网友z1 小时前
从一次手滑,我洞悉了用户输入的所有可能性(3330. 找到初始输入字符串 I)
算法
持梦远方1 小时前
C 语言基础入门:基本数据类型与运算符详解
c语言·开发语言·c++
YuTaoShao1 小时前
【LeetCode 热题 100】73. 矩阵置零——(解法二)空间复杂度 O(1)
java·算法·leetcode·矩阵
Heartoxx1 小时前
c语言-指针(数组)练习2
c语言·数据结构·算法
大熊背1 小时前
图像处理专业书籍以及网络资源总结
人工智能·算法·microsoft
满分观察网友z1 小时前
别怕树!一层一层剥开它的心:用BFS/DFS优雅计算层平均值(637. 二叉树的层平均值)
算法
江理不变情1 小时前
图像质量对比感悟
c++·人工智能