首页 > 其他分享 >Leetcode 第 409 场周赛题解

Leetcode 第 409 场周赛题解

时间:2024-09-07 23:52:50浏览次数:15  
标签:周赛 lc int 题解 复杂度 vector Leetcode dp size

Leetcode 第 409 场周赛题解

Leetcode 第 409 场周赛题解

题目1:3242. 设计相邻元素求和服务

思路

模拟,在原数组的周围补一圈 0。

代码

/*
 * @lc app=leetcode.cn id=3242 lang=cpp
 *
 * [3242] 设计相邻元素求和服务
 */

// @lc code=start
class NeighborSum
{
private:
    int g[12][12];
    int n;

public:
    NeighborSum(vector<vector<int>> &grid) : n(grid.size())
    {
        for (int i = 0; i <= n + 1; i++)
            for (int j = 0; j <= n + 1; j++)
                g[i][j] = 0;
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                g[i][j] = grid[i - 1][j - 1];
    }

    int adjacentSum(int value)
    {
        int ans = 0;
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                if (g[i][j] == value)
                    ans = g[i][j - 1] + g[i + 1][j] + g[i - 1][j] + g[i][j + 1];

        return ans;
    }

    int diagonalSum(int value)
    {
        int ans = 0;
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                if (g[i][j] == value)
                    ans = g[i - 1][j - 1] + g[i - 1][j + 1] + g[i + 1][j - 1] + g[i + 1][j + 1];
        return ans;
    }
};

/**
 * Your NeighborSum object will be instantiated and called as such:
 * NeighborSum* obj = new NeighborSum(grid);
 * int param_1 = obj->adjacentSum(value);
 * int param_2 = obj->diagonalSum(value);
 */
// @lc code=end

复杂度分析

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

空间复杂度:O(n2),其中 n 是数组 grid 的行(列)数。

题目2:3243. 新增道路查询后的最短距离 I

思路

动态规划。

定义 dp[i] 为从 0 到 i 的最短路。

用 from[i] 记录额外添加的边的终点是 i,起点列表是 from[i]。

我们可以从 i−1 到 i,也可以从 from[i][j] 到 i,这些位置作为转移来源,用其 dp 值 +1 更新 dp[i] 的最小值。

初始值:dp[i]=i。

答案:dp[n−1]。

注意:设添加的边为 l→r,只有当 dp[l]+1<dp[r] 时才更新 DP。

代码

/*
 * @lc app=leetcode.cn id=3243 lang=cpp
 *
 * [3243] 新增道路查询后的最短距离 I
 */

// @lc code=start

// 动态规划

class Solution
{
public:
    vector<int> shortestDistanceAfterQueries(int n, vector<vector<int>> &queries)
    {
        vector<int> dp(n);
        vector<vector<int>> from(n);
        // 初始化:dp[i] = i
        iota(dp.begin(), dp.end(), 0);

        vector<int> ans;
        // 状态转移
        for (vector<int> &q : queries)
        {
            int l = q[0], r = q[1];
            from[r].push_back(l);
            if (dp[l] + 1 < dp[r])
            {
                dp[r] = dp[l] + 1;
                // 更新后面的最短路
                for (int i = r + 1; i < n; i++)
                {
                    dp[i] = min(dp[i], dp[i - 1] + 1);
                    for (int j : from[i])
                    {
                        // 存在一条 j->i 的路径
                        dp[i] = min(dp[i], dp[j] + 1);
                    }
                }
            }
            ans.push_back(dp[n-1]);
        }
        return ans;
    }
};
// @lc code=end

复杂度分析

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

空间复杂度:O(n+q),其中 q 是数组 queries 的长度。

题目3:3244. 新增道路查询后的最短距离 II

思路

贪心。

由于题目保证添加的边(捷径)不会交叉,从贪心的角度看,遇到捷径就走捷径是最优的。所有被跳过的城市都不可能再出现在最短路了,直接删除掉。

代码

/*
 * @lc app=leetcode.cn id=3244 lang=cpp
 *
 * [3244] 新增道路查询后的最短距离 II
 */

// @lc code=start
class Solution
{
public:
    vector<int> shortestDistanceAfterQueries(int n, vector<vector<int>> &queries)
    {
        set<int> s; // 存储所有城市的编号
        // 将每个城市加入到 set 中
        for (int i = 0; i < n; i++)
            s.insert(i);

        vector<int> ans;
        for (vector<int> &q : queries)
        {
            // [l, r) 之间的所有城市不可能在最短路里
            auto l = s.upper_bound(q[0]), r = s.lower_bound(q[1]);
            s.erase(l, r);
            // 剩余节点数减 1 即为当前的最短路径长度
            ans.push_back(s.size() - 1);
        }
        return ans;
    }
};
// @lc code=end

复杂度分析

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

空间复杂度:O(n)。

题目4:3245. 交替组 III

思路

树状数组。

题解:https://leetcode.cn/problems/alternating-groups-iii/solutions/2869147/cong-yi-dao-nan-yi-bu-bu-tui-dao-pythonj-jho9/

代码

/*
 * @lc app=leetcode.cn id=3245 lang=cpp
 *
 * [3245] 交替组 III
 */

// @lc code=start
class FenwickTree
{
    vector<array<int, 2>> tree;

public:
    FenwickTree(int n) : tree(n + 1) {}

    // op=1,添加一个 size
    // op=-1,移除一个 size
    void update(int size, int op)
    {
        for (int i = tree.size() - size; i < tree.size(); i += i & -i)
        {
            tree[i][0] += op;
            tree[i][1] += op * size;
        }
    }

    // 返回 >= size 的元素个数,元素和
    pair<int, int> query(int size)
    {
        int cnt = 0, sum = 0;
        for (int i = tree.size() - size; i > 0; i &= i - 1)
        {
            cnt += tree[i][0];
            sum += tree[i][1];
        }
        return {cnt, sum};
    }
};

class Solution
{
public:
    vector<int> numberOfAlternatingGroups(vector<int> &a, vector<vector<int>> &queries)
    {
        int n = a.size();
        set<int> s;
        FenwickTree t(n);

        // op=1,添加一个结束位置 i
        // op=-1,移除一个结束位置 i
        auto update = [&](int i, int op)
        {
            auto it = s.lower_bound(i);
            int pre = it == s.begin() ? *s.rbegin() : *prev(it);
            int nxt = it == s.end() ? *s.begin() : *it;

            t.update((nxt - pre + n - 1) % n + 1, -op); // 移除/添加旧长度
            t.update((i - pre + n) % n, op);
            t.update((nxt - i + n) % n, op); // 添加/移除新长度
        };

        // 添加一个结束位置 i
        auto add = [&](int i)
        {
            if (s.empty())
            {
                t.update(n, 1);
            }
            else
            {
                update(i, 1);
            }
            s.insert(i);
        };

        // 移除一个结束位置 i
        auto del = [&](int i)
        {
            s.erase(i);
            if (s.empty())
            {
                t.update(n, -1);
            }
            else
            {
                update(i, -1);
            }
        };

        for (int i = 0; i < n; i++)
        {
            if (a[i] == a[(i + 1) % n])
            {
                add(i); // i 是一个结束位置
            }
        }

        vector<int> ans;
        for (auto &q : queries)
        {
            if (q[0] == 1)
            {
                if (s.empty())
                {
                    ans.push_back(n); // 每个长为 size 的子数组都符合要求
                }
                else
                {
                    auto [cnt, sum] = t.query(q[1]);
                    ans.push_back(sum - cnt * (q[1] - 1));
                }
            }
            else
            {
                int i = q[1];
                if (a[i] == q[2])
                { // 无影响
                    continue;
                }
                int pre = (i - 1 + n) % n, nxt = (i + 1) % n;
                // 修改前,先去掉结束位置
                if (a[pre] == a[i])
                {
                    del(pre);
                }
                if (a[i] == a[nxt])
                {
                    del(i);
                }
                a[i] ^= 1;
                // 修改后,添加新的结束位置
                if (a[pre] == a[i])
                {
                    add(pre);
                }
                if (a[i] == a[nxt])
                {
                    add(i);
                }
            }
        }
        return ans;
    }
};
// @lc code=end

复杂度分析

时间复杂度:O((n+q)logn),其中 n 是数组 colors 的长度,q 是数组 queries 的长度。

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

标签:周赛,lc,int,题解,复杂度,vector,Leetcode,dp,size
From: https://blog.csdn.net/ProgramNovice/article/details/141754447

相关文章

  • 题解:AT_abc370_c [ABC370C] Word Ladder
    说句闲话并不会有更好的阅读体验。这题是一个比较奇葩的贪心、构造。也可以认为是一个数据结构略有难度的练习题。理论部分?>注:使用\(N\)表示字符串长度。一句段话题意:三个字符串\(S\)、\(T\)、\(X\),其中\(S\)和\(T\)仅包含小写字母且等长,\(X\)为空。每一个操作可以......
  • CF2002D2 DFS Checker (Hard Version) 题解
    https://codeforces.com/problemset/problem/2002/D2考虑找一个容易维护的必要条件,再证明充分性。最容易想到的是每个子树对应一个区间,子树根位于左端点sol1相邻的结点\(p_{i-1},p_i\)有两种情况:\(fa[p_i]=p_{i-1}\);叶子\(p_{i-1}\)在子树\(fa[p_i]\)中,回溯到\(fa[......
  • LCP 485. 最大连续 1 的个数[lleetcode -11]
    从今天起,我们的算法开始研究搜索,首先就是DFS深度优先搜索(depth-firstseach,DFS)在搜索到一个新的节点时,立即对该新节点进行遍历;因此遍历需要用先入后出的栈来实现,也可以通过与栈等价的递归来实现。对于树结构而言,由于总是对新节点调用遍历,因此看起来是向着“深”的方向前进......
  • abc370 A-E题解 (AtCoder Beginner Contest 370)
     A这类简单题,看清楚:OutputPrint Yes, No,or Invalid accordingtotheinstructionsintheproblemstatement. B Cstd,这样写(0->n-1,n-1->0),可以少写一个vector1#include<bits/stdc++.h>2usingnamespacestd;34intmain(){5strings,......
  • Leetcode 029 两数相除
    给你两个整数,被除数dividend和除数divisor。将两数相除,要求不使用乘法、除法和取余运算。整数除法应该向零截断,也就是截去(truncate)其小数部分。例如,8.345将被截断为8,-2.7335将被截断至-2。返回被除数dividend除以除数divisor得到的商。注意:假设我们的环境只能......
  • 题解:Toyota Programming Contest 2024#9(AtCoder Beginner Contest 370)
    总体情况这次手速够快:ABCin10min,ABCDEin30min。A-RaiseBothHands思路分类讨论很简单的。注意一定要判断\(0,0\)这种情况。Code//Problem:A-RaiseBothHands//Contest:AtCoder-ToyotaProgrammingContest2024#9(AtCoderBeginnerContest370)//URL:......
  • 天翼云存储SpinTires问题解析:d3dx9_43.dll文件丢失应对指南
    在使用天翼云存储或运行SpinTires等游戏时,有时会遇到系统提示“d3dx9_43.dll文件丢失”的错误。这个问题通常是由于DirectX组件中的d3dx9_43.dll文件未正确安装、损坏或丢失所导致的。以下是一些应对指南,帮助您解决这一问题:一、了解d3dx9_43.dll文件的重要性d3dx9_43.dll是D......
  • 【Golang】LeetCode面试经典150题:45. 跳跃游戏 II
    题干:给定一个长度为 n 的 0索引整数数组 nums。初始位置为 nums[0]。每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说,如果你在 nums[i] 处,你可以跳转到任意 nums[i+j] 处:0<=j<=nums[i] i+j<n返回到达 nums[n-1] 的最小跳跃次数......
  • 东方博宜oj题解1161-1165(c++)
    各位读者们,抱歉,因为最近的时间原因,所以更新频率比较低。1161:1161-元素插入有序数组-东方博宜OJ#include<bits/stdc++.h>usingnamespacestd;intmain(){ intn,s,c; cin>>c>>n; inta[n];//定义数组 for(inti=0;i<n;i++){ cin>>a[i]; } s=n;//设c是最大的......
  • 洛谷 P4829 kry loves 2048——题解
    洛谷P4829题解传送锚点摸鱼环节kryloves2048题目背景kls是一个人赢。题目描述kls最近在玩一款类似2048的游戏,规则是这样的:一开始,有\(n\)个方块,每个方块上有一个\(1\)到\(m\)的整数。kls可以进行两种操作:选择两个数字相同的方块(不一定要相邻),将它们合并成一个数字为......