(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; }