【系统设计】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 = ;
}
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 > )){
StrToken * newToke = new StrToken();
newToke->counter = ;
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 == ){
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+))){
StrToken * newToke = new StrToken();
newToke->counter = toke->counter+;
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 > ){
if(prev == keyList.getHead() ||
(prevToke!=NULL && prevToke->counter < (toke->counter - ))){
StrToken * newToke = new StrToken();
newToke->counter = toke->counter - ;
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();
*/
【系统设计】432. 全 O(1) 的数据结构的更多相关文章
- Java实现 LeetCode 432 全 O(1) 的数据结构
432. 全 O(1) 的数据结构 实现一个数据结构支持以下操作: Inc(key) - 插入一个新的值为 1 的 key.或者使一个存在的 key 增加一,保证 key 不为空字符串. Dec(ke ...
- [LeetCode] All O`one Data Structure 全O(1)的数据结构
Implement a data structure supporting the following operations: Inc(Key) - Inserts a new key with va ...
- leetcode难题
4 寻找两个有序数组的中位数 35.9% 困难 10 正则表达式匹配 24.6% 困难 23 合并K个排序链表 47.4% 困难 25 K ...
- C#LeetCode刷题-设计
设计篇 # 题名 刷题 通过率 难度 146 LRU缓存机制 33.1% 困难 155 最小栈 C#LeetCode刷题之#155-最小栈(Min Stack) 44.9% 简单 173 二叉搜索 ...
- Pandas_基础_全
Pandas基础(全) 引言 Pandas是基于Numpy的库,但功能更加强大,Numpy专注于数值型数据的操作,而Pandas对数值型,字符串型等多种格式的表格数据都有很好的支持. 关于Numpy的 ...
- Python全栈之路----目录
Module1 Python基本语法 Python全栈之路----编程基本情况介绍 Python全栈之路----常用数据类型--集合 Module2 数据类型.字符编码.文件操作 Python全栈之路 ...
- 《数据结构-C语言版》(严蔚敏,吴伟民版)课本源码+习题集解析使用说明
<数据结构-C语言版>(严蔚敏,吴伟民版)课本源码+习题集解析使用说明 先附上文档归类目录: 课本源码合辑 链接☛☛☛ <数据结构>课本源码合辑 习题集全解析 链接☛☛☛ ...
- 9-11-Trie树/字典树/前缀树-查找-第9章-《数据结构》课本源码-严蔚敏吴伟民版
课本源码部分 第9章 查找 - Trie树/字典树/前缀树(键树) ——<数据结构>-严蔚敏.吴伟民版 源码使用说明 链接☛☛☛ <数据结构-C语言版>(严蔚 ...
- 9-9-B+树-查找-第9章-《数据结构》课本源码-严蔚敏吴伟民版
课本源码部分 第9章 查找 - B+树 ——<数据结构>-严蔚敏.吴伟民版 源码使用说明 链接☛☛☛ <数据结构-C语言版>(严蔚敏,吴伟民版)课本源码+习题 ...
随机推荐
- Qt-QML-Charts-ChartView-编译错误-ASSERT: "!"No style available without QApplication!
昨天本来是回家想好好琢磨一下使用Chart来绘制曲线的,奈何在建立项目的时候也就卡住了,加上心情比较烦躁,也没有耐心寻找答案就草草了事.所以今天继续搞定这个. 上图是Qt 的编译错误截图 QML de ...
- Android Studio怎样创建App项目
然后等待大约N分钟: 默认的是Android模式, 改为Project模式更符合我们的习惯:
- 巧用浏览器F12调试器定位系统前后端bug
做测试的小伙伴可能用过httpwatch,firebug,fiddler,charles等抓包(数据包)工具,但实际上除了这些还有一个简单实用并的抓包工具,那就是浏览器的F12调试器. httpwat ...
- python操作符及其循环语句(非常全)
//2018.10.14 1. Windows + R可以直接进行运行cmd 2. Random.randint(a,b):产生a-b的任意一个整数,在IDLE里面运行时需要注意在前面写好调用impo ...
- Java开发工程师(Web方向) - 03.数据库开发 - 第1章.JDBC
第1章--JDBC JDBC基础 通过Java Database Connectivity可以实现Java程序对后端数据库的访问 一个完整的数据库部署架构,通常是由客户端和服务器端两部分组成 客户端封 ...
- servlet和Jsp的复习整理
servlet 1.生命周期 a.构造方法.生成一个servlet b.init()方法.当开启服务器时,servlet第一次被装载,servlet引擎调用这个servlet的init()的方法,只调 ...
- 两种缓存淘汰算法LFU&LRU
LRU全称是Least Recently Used,即最近最久未使用的意思. LRU算法的设计原则是:如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小.也就是说,当限定的空间已 ...
- Bootstrap框架(组件)
按钮组 通过按钮组容器把一组按钮放在同一行里.通过与按钮插件联合使用,可以设置为单选框或多选框的样式和行为. 按钮组中的工具提示和弹出框需要特别的设置 当为 .btn-group 中的元素应用工具提示 ...
- C指针函数中的局部变量返回
所谓指针函数其实就是 :一个函数的返回值为指针. 指针函数定义:返回类型标识符* 函数名(形参列表){函数体} eg: int* fun1(int n){} 指针函数和局部变量返回解析: 简 ...
- Attention注意力机制介绍
什么是Attention机制 Attention机制通俗的讲就是把注意力集中放在重要的点上,而忽略其他不重要的因素.其中重要程度的判断取决于应用场景,拿个现实生活中的例子,比如1000个人眼中有100 ...