双向链表和哈希表的结合

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();
 */
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值