• 序列相关的趣题 之四


    (8) 给定一个英文单词,消除当中反复的字母,仅仅能删掉字母。不能交换字母顺序,最后原单词中每一个字母仅仅出现一次,求字典序最小的结果。

    这是toj一个题。百度面试也问过,原题见 http://acm.tju.edu.cn/toj/showp3257.html

    此题我很喜欢,巧妙之处是其算法是O(n)的…… 。我们一个字母一个字母增加序列,一旦来了一个比較“小”的字母,由于我们须要字典顺序最小。我们希望它尽可能靠前。

    所以我们试图“冒泡”似的把小的往前面送。经过尾部那些较大的字母临时扔掉。假设它们在后面还会出现的话。后面会增加进来。可是假设我们经过的字母后面再也不出现了。冒泡也就停止了,这个较小的字母也仅仅能临时停在这里了。这符合我们的直觉。“最后一次出现”的大字母是实用的,由于我们终于不能少字母。

    题目比較简单,但须要细细思考。

    上我的代码:

    #include <cstdio>
    #include <cstring>
    #include <stack>
    #include <string>
    #include <vector>
    using namespace std;
    
    char s[1024],answer[30];
    int main() {
    int z;
    	for (scanf("%d",&z);z;--z) {
    		scanf("%s",s);
    		stack<int> st;
    		vector<int> num(26,0);
    		for (int i = 0; s[i]; ++i) {
    			++num[s[i] - 'a'];
    		}
    		vector<bool> have(26,false);
    		for (int i = 0; s[i]; ++i) {
    			int c = s[i] - 'a';
    			--num[c];
    			if (!have[c]) {
    				for  (;(!st.empty()) && num[st.top()] && (st.top() > c); have[st.top()] = false,st.pop())
    				;
    				st.push(c);
    				have[c] = true;
    			}
    		}
    		answer[st.size()] = 0;
    		for (int i = st.size(); !st.empty(); answer[--i] = st.top() + 'a',st.pop())
    		;
    		puts(answer); 	
    			
    	}
    	return 0;
    }
    	
    

    代码里记录了一个字母后面还要出现多少次,还有它是否已经在堆栈中了。由于每一个字母最多进出堆栈一次,所以复杂度是O(n)的。


    (9) 一个特殊的“堆栈”,仅仅有push_back,push_front和pop_back三种操作。操作数的顺序就是1-n, 给出最后弹出数的顺序,问之前操作的顺序怎样或者根本不可能。

    这个题是网上看到的rocket fuel的面试。由于是面试题。没地方提交…… 代码也是自己想的。欢迎提意见。

    首先假设弹出的数在数组a里面,而且数组a是1-n的一个排列,即数组a不缺少数。不反复数,没有非法的超出范围的数。

    由于全部的数是按1-n的顺序增加进去的,假设一个数x先被弹出来,小于x的数应该都在里面了。它们在里面的顺序怎样呢? 这个和“时间戳”相关了,先弹出来的肯定在尾部。所以我们先统计每一个数的“时间戳”。然后在弹出x之前,依据小于x的时间戳。决定那些数每一个是push_front还是push_back。

    用双端队列模拟。最后看一下队尾是不是我要的那个数就能够了。我定义了一个结构op。里面是pair<int,int>第一个表示操作数,第二个表示前进、后进、出。事实上第一维能够省略的。

    代码:

    bool solution(vector<int> &a,vector<pair<int,int> > &op) {
    int n = a.size();
    vector<int> ord(n + 1);
    	for (int i = 0; i < n; ++i) {
    		ord[a[i]] = i;
    	}
    	deque<int> q;
    	/*
    		1 push_back
    		-1 push_front
    		0 pop_back
    	*/
    	op.clear();
    	for (int i = 1, j = 0;j < n; ++j) {
    		for (;i <= a[j]; ++i) {
    			if ((q.empty()) || (ord[q.back()] > ord[i])) {
    				q.push_back(i);
    				op.push_back(make_pair(i, 1));
    			}
    			else {
    				q.push_front(i);
    				op.push_back(make_pair(i, 0));
    			}
    				
    		}
    		if ((q.empty()) || (q.back() != a[j])) {
    			op.clear();
    			return false;
    		}
    		q.pop_back();
    		op.push_back(make_pair(a[j], 0));
    	}
    	return true;
    }




  • 相关阅读:
    Java_基础_内存管理
    Reflux中文教程——action
    Reflux中文教程——概览
    包含块、层叠上下文、BFC
    DOM编程的性能问题
    JavaScript数据存取的性能问题
    闭包
    JavaScript中的继承
    JavaScript中的静态成员
    JavaScript中的私有属性
  • 原文地址:https://www.cnblogs.com/mqxnongmin/p/10959275.html
Copyright © 2020-2023  润新知