《六月集训》(第十三天)——双向链表

本文介绍了如何使用双向链表和哈希表来实现一个全O(1)时间复杂度的数据结构。通过双向链表存储字符串并保持按出现次数单调不降排序,哈希表用于快速查找。文章详细解析了插入、删除、增加和减少计数以及查找最大和最小字符串的操作,并给出了源码实现。
摘要由CSDN通过智能技术生成

前言

        欢迎大家积极在评论区留言发表自己的看法,知无不言,言无不尽,养成每天刷题的习惯,也可以自己发布优质的解题报告,供社区一同鉴赏,吸引一波自己的核心粉丝。
        今天是六月集训第十三天:双向链表🔥🔥🔥🔥🔥
        一支笔,一杯茶,一道困难题想一天。
在这里插入图片描述

一、练习题目

        432. 全 O(1) 的数据结构

二、算法思路

  • 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、具体过程写在了注释里面。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值