整体思路:一个循环队列同时使用节点的计数来标记节点的新旧信息,如果有新节点加入时,就把最旧的节点清空,将新节点加入。具体画一下图比较好理解。
#include <iostream> #include <vector> #include <map> #include <queue> using namespace std; static const int LEN = 5; int main(){ vector<int> vires(LEN,-1);//保存结果 vector<int> vi(LEN,-1);//循环数组 deque<int> empty;//上层为空的结点在结果数组中的下标 map<int,int> mii,miires;//mii记录vi里的点的计数,miires记录的是点在vires里的下标 for(int i=0;i<LEN;++i){ empty.push_back(i); } int itp,ict=0; while(cin>>itp){ if(mii.count(vi[ict])){//如果存在,删除循环队列中原来的数 --mii[vi[ict]]; if(mii[vi[ict]]==0){ empty.push_back(miires[vi[ict]]); mii.erase(mii.find(vi[ict])); } } vi[ict]=itp;//给循环队列中当前位置赋新值 mii[itp]+=1; ++ict; ict%=LEN; if(miires.count(itp)){ auto atp = empty.begin(); for(;atp!=empty.end();++atp){ if(*atp==miires[itp]) break; } if(*atp == miires[itp]) empty.erase(atp); } else{//真实存储中没有这个数,需要存进去 if(vires[empty.front()]!=-1) miires.erase(miires.find(vires[empty.front()])); vires[empty.front()]=itp; miires[itp]=empty.front(); empty.pop_front(); //print for(auto ieh:vires){ if(ieh!=-1) cout<<ieh<<" "; } cout<<endl; } } return 0; } //1 2 3 4 5 6 5 4 3 1 7 9 1 2 3 5 6 9 4 2 1
结果如下:
1 2 3 4 5 6 5 4 3 1 7 9 1 2 3 5 6 9 4 2 1 1 1 2 1 2 3 1 2 3 4 1 2 3 4 5 6 2 3 4 5 6 1 3 4 5 7 1 3 4 5 7 1 3 4 9 7 1 3 2 9 5 1 3 2 9 5 1 3 2 6 5 9 3 2 6 5 9 3 4 6 5 9 2 4 6 1 9 2 4 6
这个实现中有些地方需要在数组中查找元素,效率差就差在这里,如果需要时间复杂度为O(1)的插入与删除,还是得用hashMap+双向链表。