【系统设计】432. 全 O(1) 的数据结构
题目:
使用栈实现队列的下列操作: push(x) -- 将一个元素放入队列的尾部。 pop() -- 从队列首部移除元素。 peek() -- 返回队列首部的元素。 empty() -- 返回队列是否为空。 注意: 你只能使用标准的栈操作-- 也就是只有push to top, peek/pop from top, size, 和 is empty 操作是合法的。 你所使用的语言也许不支持栈。你可以使用 list 或者 deque (双端队列) 来模拟一个栈,只要是标准的栈操作即可。 假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)。
本题解题思路:
思考过程中考虑到可以用两个map来解决该问题,但发现比较麻烦,后自己写了一个解决方案:
核心数据结构:
struct DoubleListNode{ void * val; DoubleListNode * pre; DoubleListNode * next; DoubleListNode(void * x):val(x){ pre = NULL; next = NULL; } }; struct StrToken{ int counter; set<string> strs; };
用一个排序的双向链表来存储所有的key和key的计数,数列的计数从小到大。
如果返回最小计数的key,则返回队列中的头元素,如果返回最大计数的key,则返回队列的最末位的元素;
插入元素:
如果发现该key已经存在map中,则找到该节点,将该key插入到其计算加1的链表节点中去,同时更新map映射;如果发现该key不存在,则将该key插入到计算为1的节点中去,同时更新map映射。
删除元素:
如果发现该key已经存在map中,则找到该节点,将该key插入到其计算减一的链表节点中去同时更新MAP映射。
返回最大值:
由于链表是按照计算的大小排列的,返回链表中的最后端的元素即可。
返回最小值:
由于链表是按照计算的大小排列的,返回链表中的最前端的元素即可。
源代码如下,leetcode执行时间为40ms
struct DoubleListNode{ void * val; DoubleListNode * pre; DoubleListNode * next; DoubleListNode(void * x):val(x){ pre = NULL; next = NULL; } }; struct StrToken{ int counter; set<string> strs; }; class DoubleLinkList{ public: DoubleLinkList(){ head = new DoubleListNode(NULL); tail = new DoubleListNode(NULL); head->next = tail; tail->pre = head; cnt = 0; } bool insertHead(DoubleListNode * node){ if(NULL == node || NULL == head){ return false; } node->next = head->next; node->pre = head; head->next->pre = node; head->next = node; cnt++; return true; } bool insertTail(DoubleListNode * node){ if(NULL == node || NULL == tail){ return false; } node->next = tail; node->pre = tail->pre; tail->pre->next = node; tail->pre = node; cnt++; return true; } DoubleListNode * getHead(){ return this->head; } DoubleListNode * getTail(){ return this->tail; } DoubleListNode * getNext(const DoubleListNode * target){ if(NULL == target){ return NULL; } return target->next; } DoubleListNode * getPrev(const DoubleListNode * target){ if(NULL == target){ return NULL; } return target->pre; } bool isHead(const DoubleListNode * target){ if(head == target){ return true; }else{ return false; } } bool isTail(const DoubleListNode * target){ if(tail == target){ return true; }else{ return false; } } bool deleteTarget(DoubleListNode * node){ if(NULL == node || node == head || node == tail){ return false; } if(!node->pre || !node->next){ return false; } node->pre->next = node->next; node->next->pre = node->pre; node->next = NULL; node->pre = NULL; if(node->val){ delete node->val; node->val = NULL; } delete node; node = NULL; return true; } bool insertBefore(DoubleListNode * target,DoubleListNode * node){ if(NULL == target || NULL == node){ return false; } node->pre = target->pre; node->next = target; target->pre->next = node; target->pre = node; cnt++; return true; } bool insertAfter(DoubleListNode * target,DoubleListNode * node){ if(NULL == target || NULL == node){ return false; } node->pre = target; node->next = target->next; target->next->pre = node; target->next = node; cnt++; return true; } int length(){ return cnt; } bool isEmpty(){ if(head->next == tail){ return true; }else{ return false; } } private: struct DoubleListNode * head; struct DoubleListNode * tail; int cnt; }; class AllOne { public: /** Initialize your data structure here. */ AllOne() { } /** Inserts a new key <Key> with value 1. Or increments an existing key by 1. */ void inc(string key) { if(keyMap.find(key) == keyMap.end()){ /*we wiil insert the first node*/ DoubleListNode * head = keyList.getHead(); DoubleListNode * next = keyList.getNext(head); StrToken * toke = (StrToken *)(next->val); /*we will add a new node in to the linklist*/ if(keyList.isEmpty() || (toke != NULL && toke->counter > 1)){ StrToken * newToke = new StrToken(); newToke->counter = 1; newToke->strs.insert(key); DoubleListNode * newNode = new DoubleListNode(newToke); keyList.insertHead(newNode); keyMap[key] = newNode; }else{/*we add the key in to the token*/ if( NULL != toke && toke->counter == 1){ toke->strs.insert(key); keyMap[key] = next; } } }else{ map<string,DoubleListNode *>::iterator it = keyMap.find(key); DoubleListNode * node = it->second; StrToken * toke = (StrToken *)(node->val); toke->strs.erase(key); DoubleListNode * next = keyList.getNext(node); StrToken * nextToke = NULL; if(next != keyList.getTail()){ nextToke = (StrToken *)(next->val); } if(next == keyList.getTail() || (nextToke!=NULL && nextToke->counter > (toke->counter+1))){ StrToken * newToke = new StrToken(); newToke->counter = toke->counter+1; newToke->strs.insert(key); DoubleListNode * newNode = new DoubleListNode(newToke); keyList.insertAfter(node,newNode); keyMap[key] = newNode; }else{ if(nextToke){ nextToke->strs.insert(key); keyMap[key] = next; } } if(toke->strs.empty()){ keyList.deleteTarget(node); } } //debug(); } /** Decrements an existing key by 1. If Key's value is 1, remove it from the data structure. */ void dec(string key) { if(keyMap.find(key) == keyMap.end()){ return; } map<string,DoubleListNode *>::iterator it = keyMap.find(key); DoubleListNode * node = it->second; StrToken * toke = (StrToken *)(node->val); toke->strs.erase(key); DoubleListNode * prev = keyList.getPrev(node); StrToken * prevToke = NULL; if(prev != keyList.getHead()){ prevToke = (StrToken *)(prev->val); } if(toke->counter > 1){ if(prev == keyList.getHead() || (prevToke!=NULL && prevToke->counter < (toke->counter - 1))){ StrToken * newToke = new StrToken(); newToke->counter = toke->counter - 1; newToke->strs.insert(key); DoubleListNode * newNode = new DoubleListNode(newToke); keyList.insertBefore(node,newNode); keyMap[key] = newNode; }else{ if(prevToke){ prevToke->strs.insert(key); keyMap[key] = prev; } } }else{ keyMap.erase(key); } if(toke->strs.empty()){ keyList.deleteTarget(node); } //debug(); } /** Returns one of the keys with maximal value. */ string getMaxKey() { string res; if(keyList.isEmpty()){ return res; } DoubleListNode * node = keyList.getPrev(keyList.getTail()); StrToken * toke = (StrToken *)(node->val); return *(toke->strs.begin()); } /** Returns one of the keys with Minimal value. */ string getMinKey() { string res; if(keyList.isEmpty()){ return res; } DoubleListNode * node = keyList.getNext(keyList.getHead()); StrToken * toke = (StrToken *)(node->val); return *(toke->strs.begin()); } void debug(){ cout<<endl; DoubleListNode * node = keyList.getNext(keyList.getHead()); for(;node!=keyList.getTail();node = keyList.getNext(node)){ StrToken * toke = (StrToken *)(node->val); cout<<"cnt:"<<toke->counter<<endl; set<string>::iterator it = toke->strs.begin(); for(;it!=toke->strs.end();++it){ cout<<*it<<" "; } cout<<endl; } } private: map<string,DoubleListNode *> keyMap; DoubleLinkList keyList; }; /** * Your AllOne object will be instantiated and called as such: * AllOne obj = new AllOne(); * obj.inc(key); * obj.dec(key); * string param_3 = obj.getMaxKey(); * string param_4 = obj.getMinKey(); */