Early Order(单调栈)

链接
题意:
给定长度为 n n n的数列,保证数列中出现数字大小 1 ≤ a i ≤ k 1\le a_i\le k 1aik,要求给出包含 [ 1 , k ] [1,k] [1,k]所有数字(每个只出现一次)的字典序最小子序列。(子序列可以不连续)
思路:
由于要求字典序最小,所以要让序列尽可能的单调递增。采用单调栈维护递增数列。
入栈与出栈原则:

  1. 在栈中出现过的元素,表示在栈中的这个元素可以作为当前答案,不予以处理,直接continue
  2. 当前元素比栈顶元素大 ⇒ \Rightarrow 直接加入栈
  3. 当前元素比栈顶元素小,找到之前所有在后面还会出现,同时大小比当前元素大的元素进行弹栈。

AC代码:

int a[maxn], has[maxn],ed[maxn];
int q[maxn];
int tail, head;
int main()
{
    
    
	int n, k;
	cin >> n >> k;
	for (int i = 1; i <= n; i++) {
    
    
		cin >> a[i];
	}
	for (int i = n; i > 0; i--) {
    
    
		if (ed[a[i]] == 0) {
    
    
			ed[a[i]] = i;
		}
	}
	q[++tail] = a[1];
	head++;
	has[a[1]] = 1;
	for (int i = 2; i <= n; i++) {
    
    
		if (has[a[i]])continue;
		if (a[i] > q[tail]) {
    
     
			q[++tail] = a[i]; 
			has[a[i]] = 1; 
		}
		if (a[i] < q[tail]) {
    
    
			while (tail >= head && ed[q[tail]] > i&&a[i] < q[tail]) {
    
    
				has[q[tail]] = 0;
				tail--;
			}
			q[++tail] = a[i];
			has[a[i]] = 1;
		}
	}
	for (int i = head; i <= tail; i++) {
    
    
		cout << q[i] << " ";
	}
	cout << endl;
	return 0;
}

Guess you like

Origin blog.csdn.net/weixin_44986601/article/details/114581657
Recommended