题目
牌堆里有n
张扑克牌,有m
次操作,每次操作将对应的牌放到牌堆顶,求最后牌堆的序列。
输入序列为从牌堆顶到牌堆底。1 <= n, m <= 1e5
示例
输入:
5
1 2 3 4 5
3
3 2 3
输出:
3 2 1 4 5
思路
如果直接模拟每一次放堆顶操作,不管用链表还是数组都需要 O(n)
的时间复杂度去找到对应的牌或者调整牌序,总的复杂度就是 O(mn)
,不满足要求。
其实并不需要模拟每次操作,只需要关注对每一张牌的最后一次操作,这些操作序列才最终决定了牌堆的顺序。
解法
反向遍历操作数组,每次遇到未出现的数 x
,说明这是x
的最后一次操作,将其加入答案数组和标记集合中;
正向遍历牌堆数组,每次遇到不在标记集合中的数y
,说明 y
从未被操作过,将其加入答案数组。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| #include <bits/stdc++.h> #include <iostream> using namespace std;
template<typename T> inline void printVec(vector<T> v) { cout << "vector: "; for (size_t i=0; i<v.size(); ++i) { cout << v[i] << (i < v.size()-1 ? " " : ""); } cout << endl; } template<typename T> inline void printSet(unordered_set<T> st) { cout << "set: "; for (auto iter = st.begin(); iter != st.end(); iter++) { cout << *iter << " "; } cout << endl; }
int main() { int n, m; cin >> n; vector<int> nums(n); for (int i=0; i<n; ++i) { cin >> nums[i]; } cin >> m; vector<int> ops(m); for (int i=0; i<m; ++i) { cin >> ops[i]; } unordered_set<int> st; vector<int> res; for (auto iter = ops.rbegin(); iter != ops.rend(); iter++) { auto num = *iter; if (st.find(num) == st.end()) { res.emplace_back(num); st.insert(num); } } for (int num : nums) { if (st.find(num) == st.end()) { res.emplace_back(num); } } printVec(res); return 0; }
|
扩展
面试官是个ACM选手,问有没有其他空间复杂度 O(1)
的方法 😭
“下次一定” 👌 “明天再说“ 🙉 晚安 🛌