前言
欢迎大家积极在评论区留言发表自己的看法,知无不言,言无不尽,养成每天刷题的习惯,也可以自己发布优质的解题报告,供社区一同鉴赏,吸引一波自己的核心粉丝。
今天是六月集训第十三天:双向链表🔥🔥🔥🔥🔥
一支笔,一杯茶,一道困难题想一天。
一、练习题目
二、算法思路
- 1、432. 全 O(1) 的数据结构:这题是按照题解的思路来的,双向链表的专题,同时又要O(1)的时间查询,使用的是hash表。🔥🔥🔥🔥🔥
(1)利用双向链表存储所有字符串信息,链表结点上设置两个值,一个是字符串的值,一个是字符串出现的次数。并且链表按照次数单调不降排列;
(2)再需要一个哈希表键值对,键值是字符串,值为双向链表的结点,可以快速查到字符串对应的结点;
(3)inc,在哈希表中查找对应字符串是否存在,如果不存在则直接插入双向链表的头部;否则,查找对应的结点,并且对计数器进行自增,然后和下一个结点比较,然后根据大小关系进行交换;
(4)dec,一定存在于哈希表中,取得对应的结点,计数器进行自减,减完如果发现计数为零,则在对应双向链表进行删除操作;否则直接查找对应结点,然后和前一个结点比较,进行交换;
(5)查找最大和最小,因为是升序直接找在双向链表查找头和尾就可以。
三、源码剖析
// 432. 全 O(1) 的数据结构
struct Binode
{
string key;
int count;
Binode *prev, *next;
Binode() {
prev = next = nullptr;
}
};
class AllOne {
Binode *head, *tail;
unordered_map<string, Binode*> hash;
void swap(string &a, string &b) {
string temp = a;
a = b;
b = temp;
}
void swap(int &a, int &b) {
int temp = a;
a = b;
b = temp;
}
public:
AllOne() {
head = tail = nullptr;
hash.clear();
}
void insert(Binode* node) {
if(head == nullptr) {
head = tail = node;
return;
}
// 头插法,在链表的头部插入一个结点
head->prev = node;
node->next = head;
head = node;
}
void del(Binode* node) {
// 修改前一个结点的后继
if(node->prev) {
node->prev->next = node->next;
} else {
head = node->next; // 更新头结点
}
// 修改后一个结点的前驱
if(node->next) {
node->next->prev = node->prev;
} else {
tail = node->prev; // 更新尾结点
}
}
// 向后按照key出现的次数进行升序排序
void balance_backward(Binode *node) {
while(node && node->next) {
if(node->count > node->next->count) {
Binode *nnext = node->next;
swap(node->key, nnext->key);
swap(node->count, nnext->count);
// 交换hash表中键值映射的结点
Binode *tmp = hash[node->key];
hash[node->key] = hash[nnext->key];
hash[nnext->key] = tmp;
}
node = node->next;
}
}
// 向前按照key出现的次数进行升序排序
void balance_forward(Binode *node) {
while(node && node->prev) {
if(node->count < node->prev->count) {
Binode *nprev = node->prev;
swap(node->key, nprev->key);
swap(node->count, nprev->count);
// 交换hash表中键值映射的结点
Binode *tmp = hash[node->key];
hash[node->key] = hash[nprev->key];
hash[nprev->key] = tmp;
}
node = node->prev;
}
}
void inc(string key) {
auto iter = hash.find(key);
Binode *node;
if(iter == hash.end()) {
node = new Binode();
node->key = key;
node->count = 1;
hash[key] = node;
insert(node);
} else {
node = iter->second;
node->count++;
}
// count增加了,所以向后维护进行升序排列
balance_backward(node);
}
void dec(string key) {
auto iter = hash.find(key);
Binode *node = iter->second;
node->count--;
if(node ->count == 0) {
del(node);
} else {
// count 减小了向前维护
balance_forward(node);
}
}
string getMaxKey() {
if(tail == nullptr) return "";
return tail->key;
}
string getMinKey() {
if(head == nullptr) return "";
return head->key;
}
};
- 1、具体过程写在了注释里面。