LeetCode --- 410周赛

题目列表

3248. 矩阵中的蛇

3249. 统计好节点的数目

3250. 单调数组对的数目 I

3251. 单调数组对的数目 II

一、矩阵中的蛇

只要按照题目要求模拟即可,代码如下

class Solution {
public:
    int finalPositionOfSnake(int n, vector<string>& commands) {
        int i = 0, j = 0;
        for(auto s:commands){
            switch(s[0])
            {
                case 'U': i--; break; // switch 语法:记得加break,不然后面的case语句也会被执行
                case 'D': i++; break;
                case 'R': j++; break;
                case 'L': j--; break;
            }
        }
        return i * n + j;
    }
};

 二、统计好结点的数目

这题考多叉树的遍历,主要看对递归的理解。计算树中满足其子树结点个数相同的结点个数,本质还是求结点个数,只不过多了一些限制条件,只要在求结点个数的dfs代码中进行修改即可,代码如下

class Solution {
public:
    int countGoodNodes(vector<vector<int>>& edges) {
        int n = edges.size() + 1;
        // 建树
        vector<vector<int>> g(n);
        for(auto e:edges){
            g[e[0]].push_back(e[1]);
            g[e[1]].push_back(e[0]);
        }
        int ans = 0;
        // 下面的 dfs函数 抛开 flag 相关的语句,就是一个求树的结点个数的代码
        function<int(int,int)>dfs = [&](int x,int fa)->int{
            bool flag = true;
            int pre = -1;
            int res = 1;
            for(int y:g[x]){
                if(y != fa){
                    int sz = dfs(y, x);
                    res += sz;
                    if(pre == -1) pre = sz;
                    else if(flag) flag &= (pre == sz);
                }
            }
            ans += flag;
            return res;
        };
        dfs(0, -1);
        return ans;
    }
};

三、单调数组对的数目 I & II

这种算合法方案数的题目,一般都是用动态规划解题 ( 最重要的一点是去尝试定义状态,当然做多了题目会有感觉,具体如何定义状态还要结合题目具体问题具体分析 ) 这题的状态定义如下:

  • 状态定义:f[i][j] 表示 第 i 个数为 j 时,有多少个合法的方案数(单调数组对)
  • 状态转移方程:f[i][j] = sum(f[i-1][k]),其中 k <= min(j, nums[i-1]) && nums[i] - j <= nums[i-1] - k ,等价于 k <= min(j, nums[i-1], j + nums[i-1] - nums[i])
    表示第 i 个数填 j 时的合法方案由第 i - 1 个数填 k 时的合法方案数之和,其中 k 需要满足题目的要求
  • 状态初始化:当 i = 0 时,可以填任何数,都算作一种合法的方案,即 f[0][j] = 1

代码如下

class Solution {
    const int MOD = 1e9 + 7;
public:
    int countOfPairs(vector<int>& nums) {
        int n = nums.size(), m = ranges::max(nums);
        vector<vector<int>> f(n, vector<int>(m + 1, 1));
        // f[i][j] 表示 第 i 个数填 j 时,所有可能的方案数
        // f[0][j] 第 0 个数 可以任意取,都算作一个合法方案,初始化为 1
        // f[i][j] = sum(f[i-1][k]) 
        // 满足 k <= min(j, nums[i-1]) && nums[i] - j <= nums[i-1] - k
        // 等价于 k <= min(j, nums[i-1], j + nums[i-1] - nums[i])
        for(int i = 1; i < n; i++){
            for(int j = 0; j <= nums[i]; j++){
                int res = 0;
                for(int k = 0; k <= min({j, nums[i-1],j + nums[i-1] - nums[i]}); k++){
                    res = (res + f[i-1][k])%MOD;
                }
                f[i][j] = res;
            }
        }
        int ans = 0;
        for(int i = 0; i <= nums.back(); i++)
            ans = (ans + f[n-1][i])%MOD;
        return ans;
    }
};

如何优化?

这里其实显而易见,我们在计算 f[i][j] 时,最内层对 k 的循环遍历,本质就是在求前缀和,我们可以提前预处理得到,这样就能在O(1) 的时间内计算出 f[i][j],代码如下

class Solution {
    const int MOD = 1e9 + 7;
public:
    int countOfPairs(vector<int>& nums) {
        int n = nums.size(), m = ranges::max(nums);
        vector<vector<int>> f(n, vector<int>(m + 1, 1));
        // f[i][j] 表示 第 i 个数为 j 时,所有可能的方案数
        // f[0][j] 第 0 个数 可以任意取,都算作一个合法方案,初始化为 1
        // f[i][j] = sum(f[i-1][k]) 
        // 满足 k <= min(j, nums[i-1]) & nums[i] - j <= nums[i-1] - k
        // 等价于 k <= min(j, nums[i-1], j + nums[i-1] - nums[i])
        for(int i = 1; i < n; i++){
            // 预处理前缀和
            int pre[nums[i-1]+1]; pre[0] = f[i-1][0];
            for(int j = 1; j <= nums[i-1]; j++){
                pre[j] = (pre[j-1] + f[i-1][j])%MOD;
            }
            for(int j = 0; j <= nums[i]; j++){
                // int res = 0;
                // for(int k = 0; k <= min({j, nums[i-1],j + nums[i-1] - nums[i]}); k++){
                //     res = (res + f[i-1][k])%MOD;
                // }
                // f[i][j] = res;
                int x = min({j, nums[i-1],j + nums[i-1] - nums[i]});
                if(x < 0) f[i][j] = 0;
                else f[i][j] = pre[x];
            }
        }
        int ans = 0;
        for(int i = 0; i <= nums.back(); i++)
            ans = (ans + f[n-1][i])%MOD;
        return ans;
    }
};
  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LeetCode-Editor是一种在线编码工具,它提供了一个用户友好的界面编写和运行代码。在使用LeetCode-Editor时,有时候会出现乱码的问题。 乱码的原因可能是由于编码格式不兼容或者编码错误导致的。在这种情况下,我们可以尝试以下几种解决方法: 1. 检查文件编码格式:首先,我们可以检查所编辑的文件的编码格式。通常来说,常用的编码格式有UTF-8和ASCII等。我们可以将编码格式更改为正确的格式。在LeetCode-Editor中,可以通过界面设置或编辑器设置来更改编码格式。 2. 使用正确的字符集:如果乱码是由于使用了不同的字符集导致的,我们可以尝试更改使用正确的字符集。常见的字符集如Unicode或者UTF-8等。在LeetCode-Editor中,可以在编辑器中选择正确的字符集。 3. 使用合适的编辑器:有时候,乱码问题可能与LeetCode-Editor自身相关。我们可以尝试使用其他编码工具,如Text Editor、Sublime Text或者IDE,看是否能够解决乱码问题。 4. 查找特殊字符:如果乱码问题只出现在某些特殊字符上,我们可以尝试找到并替换这些字符。通过仔细检查代码,我们可以找到导致乱码的特定字符,并进行修正或替换。 总之,解决LeetCode-Editor乱码问题的方法有很多。根据具体情况,我们可以尝试更改文件编码格式、使用正确的字符集、更换编辑器或者查找并替换特殊字符等方法来解决这个问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值