5614. 找出最具竞争力的子序列 单调栈

5614. 找出最具竞争力的子序列

给你一个整数数组 nums 和一个正整数 k ,返回长度为 k 且最具 竞争力 的 nums 子序列。

数组的子序列是从数组中删除一些元素(可能不删除元素)得到的序列。

在子序列 a 和子序列 b 第一个不相同的位置上,如果 a 中的数字小于 b 中对应的数字,那么我们称子序列 a 比子序列 b(相同长度下)更具 竞争力 。 例如,[1,3,4] 比 [1,3,5] 更具竞争力,在第一个不相同的位置,也就是最后一个位置上, 4 小于 5 。

示例 1:

输入:nums = [3,5,2,6], k = 2
输出:[2,6]
解释:在所有可能的子序列集合 {[3,5], [3,2], [3,6], [5,2], [5,6], [2,6]} 中,[2,6] 最具竞争力。
示例 2:

输入:nums = [2,4,3,3,5,4,9,6], k = 4
输出:[2,3,3,4]

提示:

1 <= nums.length <= 105
0 <= nums[i] <= 109
1 <= k <= nums.length

class Solution {
public:
    vector<int> mostCompetitive(vector<int>& nums, int k) {
        int n = nums.size();
        vector<int> res(k);
        stack<int> stk;
        for(int i=0;i<n;i++){
            while(!stk.empty()&&stk.top()>nums[i]&&stk.size()+n-i>k){
                stk.pop();
            }
            if(stk.size()<k) stk.push(nums[i]);
        }
        for(int i=0;i<k;i++){
            res[k-i-1] = stk.top();
            stk.pop();
        }
        return res;

    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 最长单调递增子序列问题是指在一个序列中找到一个最长的子序列,使得这个子序列中的元素是单调递增的。对于由n个数组成的序列,可以使用动态规划算法来解决最长单调递增子序列问题。具体步骤如下: 1. 定义状态:设dp[i]表示以第i个元素结尾的最长单调递增子序列的长度。 2. 初始化状态:dp[i]的初始值为1,因为以第i个元素结尾的最长单调递增子序列至少包含它本身。 3. 状态转移方程:对于第i个元素,遍历前面的元素j(j<i),如果a[j]<a[i],则dp[i]=max(dp[i],dp[j]+1),即以第i个元素结尾的最长单调递增子序列长度为前面所有小于它的元素中最长的子序列长度加1。 4. 最终结果:遍历dp数组,找到最大值即为最长单调递增子序列的长度。 例如,对于序列{5,3,4,8,6,7},其最长单调递增子序列为{3,4,6,7},长度为4。 ### 回答2: 动态规划算法是解决最长单调递增子序列的一种有效方法。给定一个由n个数字组成的序列P[1],P[2],……,P[n],我们可以将其拆分成许多长度小于等于n的子序列。这些子序列中的最长单调递增子序列即为原序列的最长单调递增子序列(注意这里的子序列不要求连续)。 我们设D[i]为以P[i]为结尾的最长单调递增子序列的长度,则对于所有的j(1<=j<i),如果P[j]<P[i],那么有: D[i] = max(D[i], D[j]+1) 初始时,D[i]均初始化为1,表示以每个元素为结尾的最长单调递增子序列长度默认为1。从D[1]到D[n]依次计算即可得到整个序列的最长单调递增子序列长度。 接下来,我们以一个长度为10的序列为例进行演示: 设P[1]=5, P[2]=1, P[3]=4, P[4]=2, P[5]=3, P[6]=9, P[7]=7, P[8]=6, P[9]=8, P[10]=10。 首先,初始化D数组,将其所有元素设为1: D[1]=1, D[2]=1, D[3]=1, D[4]=1, D[5]=1, D[6]=1, D[7]=1, D[8]=1, D[9]=1, D[10]=1。 从i=2开始,依次计算D[2]到D[10]: D[2] = max(D[2], D[1]+1) = 2 D[3] = max(D[3], max(D[1], D[2])+1) = 2 D[4] = max(D[4], max(D[1], D[2], D[3])+1) = 2 D[5] = max(D[5], max(D[1], D[2], D[3], D[4])+1) = 3 D[6] = max(D[6], max(D[1], D[2], D[3], D[4], D[5])+1) = 4 D[7] = max(D[7], max(D[1], D[2], D[3], D[4], D[5])+1) = 4 D[8] = max(D[8], max(D[1], D[2], D[3], D[4], D[5], D[7])+1) = 4 D[9] = max(D[9], max(D[1], D[2], D[3], D[4], D[5], D[6], D[7], D[8])+1) = 5 D[10] = max(D[10], max(D[1], D[2], D[3], D[4], D[5], D[6], D[7], D[8], D[9])+1) = 6 最终D数组为 D=[1, 2, 2, 2, 3, 4, 4, 4, 5, 6],它的最大值即为原序列的最长单调递增子序列长度为6,它可以对应的子序列为[1, 4, 5, 6, 8, 10]。 ### 回答3: 最长单调递增子序列问题(Longest Increasing Subsequence,简称LIS)是一个经典的计算机科学问题,它的解法有很多种。其中比较常见的是动态规划算法和贪心算法。 动态规划算法的思路是构建一个数组dp来存储以每个数字结尾的最长单调递增子序列的长度。具体来说,假设我们已经求出了前i-1个数字结尾的最长单调递增子序列的长度dp[1]、dp[2]、……dp[i-1],那么我们可以考虑把第i个数字加入进去,看看是否能够延长截止到i的最长单调递增子序列。因此我们需要从前面的数字中找出所有小于第i个数字的数字,计算出以这些数字结尾的最长单调递增子序列的长度,然后把这些长度加1,取其中的最大值即可。具体的表达式可以写为: dp[i] = max{dp[j] + 1 | j < i && a[j] < a[i]} 其中a表示原始序列,dp数组的初始值都为1,表示每个数字本身构成一个长度为1的单调递增子序列。最终的结果即为dp数组中的最大值。 贪心算法的思路则是利用二分查找来维护一个目前为止最长的单调递增子序列。具体来说,我们从左到右遍历原始序列,然后维护一个数组d,记录目前为止已经找到的最长单调递增子序列。假设我们已经找到了前i-1个数字的最长单调递增子序列d[1]、d[2]、……d[k],并且d[k]是目前为止的最大值,那么我们可以把第i个数字插入进去。如果a[i]大于d[k],则可以直接把a[i]加到数组后面,因为它可以延长已有的最长单调递增子序列。否则,我们可以使用二分查找找到满足d[j] < a[i]的最大位置j,然后把a[i]插入到d[j+1]的位置上。因为d[j+1]是目前为止长度为j+1的单调递增子序列的末尾,所以插入a[i]以后,仍然是长度为j+2的单调递增子序列的末尾。 根据以上两种算法,我们可以解决由n个数组成的序列的最长单调递增子序列问题。不同的算法具有不同的时间和空间复杂度,选择合适的算法可以在保证正确性的前提下,提高计算效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值