432. 全 O(1) 的数据结构 - 力扣(LeetCode)
1.思路
讲述看到这一题的思路
这道题花了我大半时间研究出c++写法,如果用Java语言写的话比较好写,因为表示某些操作的时候足够方便,该思路中运用了set哈希表和双向链表,为什么会这么想呢?
首先本题要求时间复杂度均为O(1),考虑到链表的查找功能的时间复杂度为O(1),又联想到哈希表的增删操作的时间复杂度为O(1).
2.解题方法
把每次出现的字符串放在一个桶(set)中设置出现次数最小的头桶head,以及最大桶tail,那么可想而知求最终结果也就是在这中间找桶里面的字符,我们还需要一个哈希map,key记录字符串,value记录内存地址,注意这里c++的最大值为INT_MAX.
先额外设置一下插入操作insert和删除操作remove
insert()操作:
首先将cur节点的next节点指向pos节点,然后再将pos节点指向cur->next节点,
然后让cur节点和pos节点相互连接,中心思想就是把pos节点和当前cur节点的下一位互连再和当前节点cur互连。
remove()操作:
该操作可看做跳跃操作,就是将该节点的前后连起来即可,那么该节点也会自动失效,
inc()操作:
先判断key字符串是否在哈希表mp中,若不存在,可判断头桶的next桶的字符个数是否为1,若为1,则将字符串放入set中,若不存在,开辟一个字符个数为1的桶,再将其放入其中,
若该字符存在与哈希表mp中,先找到该字符对应的桶,分两种情况,若该桶后面的桶随对应的字符个数比该桶字符个数多一,则证明他们正好连续,则将mp中key的内存地址指向node->next,随后将key存入node—>next->set中,若不存在这样的桶,可在后面开辟一个这样大小字符个数的桶,newNode=new Node(key,node->val+1);随后删除该桶所对于set的key字符串,若该桶没有字符串了,直接将该桶删掉。
dec()操作:
同inc()操作的思路,稍微改动的就是先找到key对于的桶,判断该桶的val是否为1,若为1,mp直接删除key即可,若不为1,找node前面的桶的val是否为node->val-1,
然后分析方式同上,最后把该字符串从node->set表中删除,注意插入操作位set.insert(),删除操作为set.erase();然后判断该桶上面还有没有字符串,没有就删除该桶remove(node);
getMaxKey():
返回head->next所对应哈希表set的迭代器所对应的字符*(node->set.begin());
getMinKey():
返回tail->pre所对于哈希表set的迭代器所对应的字符*(node->set.bein());
3.复杂度:
复杂度
时间复杂度:所有操作均为 O(1),这里将字符串长度视作常数。
空间复杂度:O(I),其中 I是调用 inc 的次数。最坏情况下每次调用 inc传入的字符串均不相同,我们需要 O(I)大小的哈希表来存储所有字符串。
4.Code
我写了两种代码,不过思路一模一样,只是写法不同
struct Node{
unordered_set<string>set;
int val;
Node *pre,*next;
Node(string s,int c){
pre=NULL;
next=NULL;
val=c;
set.insert(s);
}
};
class AllOne {
public:
unordered_map<string,Node*>mp;
Node* head;
Node* tail;
AllOne() {
head=new Node("",0);
tail=new Node("",INT_MAX);
head->next=tail;
tail->pre=head;
}
void inc(string key) {
if(!mp.count(key)){
if(head->next->val==1){
mp[key]=head->next;
head->next->set.insert(key);
}
else{
Node *newNode=new Node(key,1);
mp[key]=newNode;
insert(head,newNode);
}
}
else{
Node *node=mp[key];
if(node->next->val==node->val+1){
mp[key]=node->next;
node->next->set.insert(key);
}
else{
Node *newNode=new Node(key,node->val+1);
mp[key]=newNode;
insert(node,newNode);
}
node->set.erase(key);
if(node->set.empty()){
remove(node);
}
}
}
void dec(string key) {
Node *node=mp[key];
if(node->val==1){
mp.erase(key);
}
else{
if(node->pre->val==node->val-1){
mp[key]=node->pre;
node->pre->set.insert(key);
}
else{
Node *newNode=new Node(key,node->val-1);
mp[key]=newNode;
insert(node->pre,newNode);
}
}
node->set.erase(key);
if(node->set.empty()){
remove(node);
}
}
void insert(Node* cur ,Node* pos){
cur->next->pre=pos;
pos->next=cur->next;
cur->next=pos;
pos->pre=cur;
}
void remove(Node* cur){
cur->pre->next=cur->next;
cur->next->pre=cur->pre;
}
string getMaxKey() {
return *(tail->pre->set.begin());
}
string getMinKey() {
return *(head->next->set.begin());
}
};
/**
* 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();
*/
struct Node{
unordered_set<string> container;
int val;
Node* pre;
Node* next;
Node(string s){
pre = NULL;
next = NULL;
val = 1;
container.insert(s);
}
};
class AllOne {
public:
unordered_map<string,Node*> list;
Node* head;
Node* tail;
/** Initialize your data structure here. */
AllOne() {
head = NULL;
tail = NULL;
}
/** Inserts a new key <Key> with value 1. Or increments an existing key by 1. */
void inc(string key) {
if(list.count(key)){ //已存在
Node* now = list[key];
if(now == tail){ //在尾节点中
if(now->container.size() == 1) now->val += 1; //可以直接修改val
else{ //需要新建一个结点
Node* newTail = new Node(key);
newTail->val = now->val+1;
tail->next = newTail;
newTail->pre = tail;
tail = newTail;
now->container.erase(key);
list[key] = tail;
}
}else{
if(now->next->val == now->val+1){ //后面挨着的结点,val+1
now->next->container.insert(key);
if(now->container.size() == 1){ //原来的结点只有1个元素,需要删除原来的结点
if(now == head){
now->next->pre = NULL;
head = now->next;
}else{
Node* prev = now->pre;
prev->next = now->next;
now->next->pre = prev;
}
}else{
now->container.erase(key);
}
list[key] = now->next;
}else{ //后面挨着的不是val+1
if(now->container.size() == 1) now->val += 1; //可以直接修改val
else{ //新建一个结点
Node* newNode = new Node(key);
newNode->val = now->val+1;
newNode->next = now->next;
newNode->pre = now;
now->next->pre = newNode;
now->next = newNode;
now->container.erase(key);
list[key] = now->next;
}
}
}
}else{ //没有出现
if(head==NULL){ //空链表,直接建立结点
head = new Node(key);
tail = head;
}else{
if(head->val == 1) head->container.insert(key); //头节点val=1,直接插入即可
else{ //建立新的头节点
Node* newHead = new Node(key);
newHead->next = head;
head->pre = newHead;
head = newHead;
}
}
list[key] = head;
}
}
/** Decrements an existing key by 1. If Key's value is 1, remove it from the data structure. */
void dec(string key) {
if(list.count(key)){
Node* now = list[key];
if(now->val == 1){ //发生在头结点上
if(now->container.size() == 1){ //只有这一个元素,需要删除结点
if(tail == head){ //只有这一个结点,删除后,链表为空
head = NULL;
tail = head;
}else{
head = head->next;
}
}else{
now->container.erase(key);
}
list.erase(key);
}else if(now == head){ //发生在头节点上
if(now->container.size() == 1) now->val-=1; //可以直接修改val
else{ //需要新建一个头节点
Node* newHead = new Node(key);
newHead->val = now->val-1;
head->pre = newHead;
newHead->next = head;
head = newHead;
now->container.erase(key);
list[key] = head;
}
}else{ //发生在其他结点上
if(now->pre->val == now->val-1){ //前面紧挨着的结点,val-1
now->pre->container.insert(key);
if(now->container.size() == 1){ //原结点只有一个元素,需要删除原结点
Node* prev = now->pre;
prev->next = now->next;
if(now!=tail) now->next->pre = prev;
else tail = prev;
}else{
now->container.erase(key);
}
list[key] = now->pre;
}else{ //前面挨着的结点,不是val-1
if(now->container.size() == 1) now->val -= 1; //只有一个元素,可以直接修改val
else{ //建立一个新的结点
Node* newNode = new Node(key);
newNode->val = now->val-1;
newNode->next = now;
newNode->pre = now->pre;
now->pre->next = newNode;
now->pre = newNode;
now->container.erase(key);
list[key] = now->pre;
}
}
}
}
}
/** Returns one of the keys with maximal value. */
string getMaxKey() {
if(tail == NULL) return "";
return *(tail->container.begin());
}
/** Returns one of the keys with Minimal value. */
string getMinKey() {
if(head == NULL) return "";
return *(head->container.begin());
}
};
/**
* 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();
*/