LeetCode --- 132双周赛

题目列表

3174. 清除数字

3175. 找到连续赢 K 场比赛的第一位玩家

3176. 求出最长好子序列 I

3177. 求出最长好子序列 II

一、清理数字

这题直接根据题目,进行模拟即可,大体的思路是遍历字符串,遇到字母就加入答案,遇到数字就去掉答案中的最后一个字母,最后返回答案(类似进栈出栈),代码如下

cpp 复制代码
class Solution {
public:
    string clearDigits(string s) {
        string ans;
        for(auto e:s){
            if(isdigit(e))  ans.pop_back();
            else ans += e;
        }
        return ans;
    }
};

二、找到连续赢k场的比赛的第一个玩家

这题的关键在于赢了的玩家会留下来和其他的玩家进行比赛,这就意味了在他之前参加比赛的人的skill都要小于他

  • 如果n个人比完了,其中没有人赢下k场比赛,那么第一个赢下k场比赛的玩家必然是skill最大的那个
  • 我们还要考虑在skill最大的玩家还没出现之前,就已经有玩家赢得k场比赛的情况

具体代码如下

cpp 复制代码
class Solution {
public:
    int findWinningPlayer(vector<int>& skills, int k) {
        int n = skills.size();
        int pos = 0, cnt = 0;
        for(int i = 1; i < n; i++){
            if(skills[pos] < skills[i])
                pos = i, cnt = 0;
            cnt++;
            if(cnt == k) return pos;
        }
        return pos;
    }
};

三、求出最长好子序列 I & II

题目要求好子序列的最长长度,是一个子序列相关的动态规划问题。

状态定义:

子序列dp问题一般有两种类型,相邻相关 和 相邻无关 (看子序列的相邻元素之间是否存在某种关系/限制),分别对应两种状态的定义套路:相邻相关:以i为结尾的子序列的______,相邻无关:前i个元素中______。

本题显然是相邻相关的子序列问题,状态定义为 dp[i][j] 表示以i为结尾的子序列中最多有j个满足相邻元素不相等的最长子序列长度

状态转移方程:

  • 当nums[i] == nums[k]时,dp[i][j] = max(dp[i][j], dp[k][j] + 1)
  • 当nums[i] != nums[k]时,dp[i][j] = max(dp[i][j], dp[k][j-1] + 1)
  • 其中 k < i

初始化:考虑 j = 0 的情况,即最多有0个相邻元素相等的情况(等价于子序列中的元素全部相同),边遍历数组便统计数组出现次数即可。

代码如下

cpp 复制代码
class Solution {
public:
    int maximumLength(vector<int>& nums, int k) {
        int n = nums.size();
        unordered_map<int,int> mp; // 记录相同元素的个数
        int ans = 0;
        vector<vector<int>> dp(n, vector<int>(k + 1));
        // 初始化
        for(int i = 0; i < n;i ++){
            dp[i][0] = ++mp[nums[i]];
            ans = max(ans, dp[i][0]);
        }
        for(int j = 1; j <= k; j++){
            dp[0][j] = dp[0][0];
        }
        for(int i = 1; i < n; i++){ // 枚举以哪个数字为结尾
            for(int j = 1; j <= k; j++){ // 枚举最多有j个相邻不相同的情况
                for(int p = 0; p < i; p ++){ // 从之前的状态进行转移
                    if(nums[i] == nums[p]) dp[i][j] = max(dp[i][j], dp[p][j] + 1);
                    else dp[i][j] = max(dp[i][j], dp[p][j-1] + 1);
                }
            }
            ans = max(ans, dp[i][k]); // 注意答案是所有以i为结尾的子序列最大长度的最大值
        }
        return ans;
    }
};

时间复杂度为O(kn^2),显然是过不了的第四问的,如何优化时间复杂度???我们需要将第三层for循环求max的时间缩短为O(1),如何做?

这里有一个技巧,我们可以将下标换成值,在去思考如何优化,即将状态定义改为 dp[x][j] 表示以x=nums[i]为结尾的最多有j个相邻不相同元素的子序列最大长度

转移方程:

  • 当 x == nums[k] 时,dp[x][j] = max(dp[x][j], dp[x][j] + 1) = dp[x][j]+1
  • 当 x != y 时,dp[x][j] = max(dp[x][j], dp[y][j-1] + 1)
  • 其中 k < i

故 dp[x][j] = max(dp[x][j],dp[y][j-1]) + 1,其中y是不等于x的出现过的数,所以我们只要维护好dp[y][j-1]的最大值就能在O(1)的时间复杂度内求出答案,即我们只要维护好前一列的最大值即可,即维护一个数组mx[j] = max(dp[y][j-1]),这里我们不需要额外关心 y == x的情况,因为dp[x][j] >= dp[x][j-1],所以不会对答案产生影响

代码如下

cpp 复制代码
class Solution {
public:
    int maximumLength(vector<int>& nums, int k) {
        unordered_map<int,vector<int>> dp;
        vector<int> mx(k+2);
        for(int x:nums){
            if(!dp.contains(x)) dp[x].resize(k+1);
            auto& f = dp[x];
            for(int j = k; j >= 0; j--){ // 这里得是从后往前遍历,正着遍历会覆盖掉之前的mx[j]
                f[j] = max(f[j], mx[j]) + 1;
                mx[j+1] = max(mx[j+1], f[j]);
            }
        }
        return mx[k+1];
    }
};

总结:上面两种状态定义的大致思路是一样的,只是从下标改为了数值,转移方程也很相似,但是在维护max时,因为状态的转移和数值有关,我们需要在下标和数值之间建立联系,但问题是这种联系不是一一对应的,导致我们很难通过数值关系找到合适的下标来进行操作,但是我们只要将状态的定义和数值直接挂钩,我们就能很轻松的发现维护max的方法。

这里大家可以记住这样的一个技巧:当我们需要对dp进行优化时,且状态的转移和数值有关,我们可以优先考虑是否能将状态参数改为数值

相关推荐
Black蜡笔小新15 小时前
自动化AI算法训练服务器DLTM助力医学影像分析进入AI智能分析新时代
人工智能·算法·自动化
手写码匠16 小时前
深入解析大模型架构之争:全能通用模型 vs 领域专精模型
人工智能·深度学习·算法·aigc
浅念-16 小时前
LeetCode 回溯算法题——综合练习
数据结构·c++·算法·leetcode·职场和发展·深度优先·dfs
列星随旋17 小时前
线段树和树状数组的学习
学习·算法
圣保罗的大教堂17 小时前
leetcode 61. 旋转链表 中等
leetcode
我爱cope18 小时前
【Agent智能体4 | 智能体AI的应用】
数据库·人工智能·职场和发展
全糖可乐气泡水18 小时前
Codex适配国产信创环境安装部署与技术适配全解析
开发语言·git·python·算法·百度
h_a_o777oah19 小时前
状态机+划分型 DP :深度解析K-划分问题下 DP 状态的转移逻辑(洛谷P2679 P2331 附C++代码)
c++·算法·动态规划·acm·状态机dp·划分型dp·滚动数组优化
05候补工程师19 小时前
从算法理想向工程现实的跨越:SLAM 核心架构、思维误区与 Nav2 实战避坑指南
人工智能·算法·安全·架构·机器人