一、题目
1、题目描述
给你一个整数数组
nums
和一个正整数k
,返回长度为k
且最具 竞争力 的nums
子序列。数组的子序列是从数组中删除一些元素(可能不删除元素)得到的序列。
在子序列
a
和子序列b
第一个不相同的位置上,如果a
中的数字小于b
中对应的数字,那么我们称子序列a
比子序列b
(相同长度下)更具 竞争力 。 例如,[1,3,4]
比[1,3,5]
更具竞争力,在第一个不相同的位置,也就是最后一个位置上,4
小于5
。
2、接口描述
python3
class Solution:
def mostCompetitive(self, nums: List[int], k: int) -> List[int]:
cpp
class Solution {
public:
vector<int> mostCompetitive(vector<int>& nums, int k) {
}
};
3、原题链接
二、解题报告
1、思路分析
F1 线段树
我们要取的k个数中,第一个数一定是原序列第一个数到第n - k + 1个数中取
否则如果第一个数在第n - k + 2到第n个数中取得话,我们是取不到k个数的
换句话说,第一个数在[1, n - k + 1]中取,取了第pre个数,第二个数只要在[pre, n - k + 2] 中取,……我们每次都取最小,那么最后取到的就是最具竞争力的子序列
由于只需要区间查询和建树,写起来还是比较容易地
F2 单调栈
我们用栈st维护当前序列,栈顶为序列最后一个元素
如果当前遍历元素nums[i]比栈顶小,并且len(st) + n - i > k(保证替换弹出栈顶后还能取到k个元素)
我们就不断弹出栈顶,然后插入x即可
这样一次遍历就能得到答案
两种方式都基于比较简单的贪心思想来使得序列在保证能取到长度k的情况下字典序尽可能的小
2、复杂度
F1: 时间复杂度: O(nlogn) 空间复杂度:O(n)
F2: 时间复杂度: O(n) 空间复杂度:O(n)
3、代码详解
F1
cpp
const int N = 1e5 + 10;
struct node {
int l, r, mi;
}tr[N << 2];
#define lc p << 1
#define rc p << 1 | 1
void build(int p, int l, int r, const vector<int>& a) {
tr[p] = { l, r, l };
if (l == r) return;
int mid = l + r >> 1;
build(lc, l, mid, a), build(rc, mid + 1, r, a);
tr[p].mi = a[tr[lc].mi - 1] <= a[tr[rc].mi - 1] ? tr[lc].mi : tr[rc].mi;
}
int query(int p, int l, int r, const vector<int>& a) {
if (l <= tr[p].l && tr[p].r <= r) return tr[p].mi;
int mid = tr[p].l + tr[p].r >> 1, res = l;
if (l <= mid) {
int t = query(lc, l, r, a);
if (a[t - 1] < a[res - 1]) res = t;
}
if (r > mid) {
int t = query(rc, l, r, a);
if (a[t - 1] < a[res - 1]) res = t;
}
return res;
}
class Solution {
public:
vector<int> mostCompetitive(vector<int>& nums, int k) {
int n = nums.size();
memset(tr, 0, sizeof tr);
build(1, 1, n, nums);
vector<int> ret;
for (int i = 1, pre = 0; i <= k; i ++ ) {
pre = query(1, pre + 1, n - k + i, nums);
ret.push_back(nums[pre - 1]);
}
return ret;
}
};
F2
python3
class Solution:
def mostCompetitive(self, nums: List[int], k: int) -> List[int]:
st = []
n = len(nums)
for i, x in enumerate(nums):
while st and x < st[-1] and len(st) + n - i > k:
st.pop()
if len(st) < k:
st.append(x)
return st