首页 > 其他分享 >数据结构设计

数据结构设计

时间:2024-09-28 18:46:02浏览次数:8  
标签:node map include ListNode val key 设计 数据结构

数据结构设计

设计有setAll功能的哈希表

  • 加时间戳
#include <vector>
#include <iostream>
#include <algorithm>
#include <unordered_map>

using namespace std;

// <key, <val, time>>
unordered_map<int, pair<int, int>> map;
int setAllVal;
int setAllTime = -1;
// 时间戳
int timeStamp = 0;

void put(int k, int v) {
    if (map.find(k) == map.end()) {
        // 不存在就加上时间戳
        map.emplace(k, make_pair(v, timeStamp++));
    } else {
        // 已经存在就修改时间戳
        map[k].first = v;
        map[k].second = timeStamp++;
    }
}

void get(int k) {
    // 不存在
    if (map.find(k) == map.end()) {
        cout << -1 << endl;
        return;
    }
    // 返回最新的值
    if (map[k].second > setAllTime)
        cout << map[k].first << endl;
    else
        cout << setAllVal << endl;
}

void setAll(int v) {
    setAllVal = v;
    setAllTime = timeStamp++;
}

int main() {
    int n;
    scanf("%d", &n);
    for (int i = 0, opt, k, v; i < n; ++i) {
        cin >> opt;
        switch (opt) {
            case 1:
                scanf("%d%d", &k, &v);
                put(k, v);
                break;
            case 2:
                scanf("%d", &k);
                get(k);
                break;
            case 3:
                scanf("%d", &v);
                setAll(v);
                break;
        }
    }
}

146. LRU 缓存

  • 用 map 定位节点在双向链表中的位置
#include <vector>
#include <iostream>
#include <algorithm>
#include <unordered_map>

using namespace std;

class LRUCache {
public:
    // 双向链表
    struct ListNode {
        int key;
        int value;
        ListNode *prev;
        ListNode *next;

        ListNode() {
            prev = nullptr;
            next = nullptr;
        }

        ListNode(int k, int v) {
            key = k;
            value = v;
            prev = nullptr;
            next = nullptr;
        }
    };

    // 用于定位 key 所对应的节点在链表中的位置
    unordered_map<int, ListNode *> map;
    // 虚拟头尾节点
    ListNode *dummyHead;
    ListNode *dummyTail;
    int capacity;
    int size;

    LRUCache(int capacity) {
        LRUCache::capacity = capacity;
        size = 0;
        dummyHead = new ListNode();
        dummyTail = new ListNode();
        dummyHead->next = dummyTail;
        dummyTail->prev = dummyHead;
    }

    // 插入到最后
    void addToTail(ListNode *node) {
        node->next = dummyTail;
        node->prev = dummyTail->prev;
        dummyTail->prev->next = node;
        dummyTail->prev = node;
    }

    // 将最近操作过的节点放到双向链表的表尾
    // 表头是最近最久未使用的节点
    void moveToTail(ListNode *node) {
        // 断开
        node->prev->next = node->next;
        node->next->prev = node->prev;
        addToTail(node);
    }

    // 删除首个节点
    void removeHead() {
        ListNode *node = dummyHead->next;
        dummyHead->next->next->prev = dummyHead;
        dummyHead->next = dummyHead->next->next;
        delete node;
        node = nullptr;
    }

    int get(int key) {
        // 不存在
        if (map.find(key) == map.end()) return -1;
        // 存在,就挪到末尾然后返回
        moveToTail(map[key]);
        return map[key]->value;
    }

    void put(int key, int value) {
        if (map.find(key) == map.end()) {
            // 超出容量就删除最近最久未使用的
            if (++size > capacity) {
                map.erase(dummyHead->next->key);
                removeHead();
            }
            // 不存在就新建
            ListNode *node = new ListNode(key, value);
            addToTail(node);
            map.emplace(key, node);
        } else {
            // 已经存在就修改
            map[key]->value = value;
            moveToTail(map[key]);
        }
    }
};

380. O(1) 时间插入、删除和获取随机元素

  • 用 map 定位元素在动态数组中的位置,删除时,转化成删除末尾元素,不让动态数组中有空位
#include <vector>
#include <iostream>
#include <algorithm>
#include <unordered_map>

using namespace std;

class RandomizedSet {
public:
    vector<int> arr;
    // <val, index>
    unordered_map<int, int> map;

    RandomizedSet() {

    }

    bool insert(int val) {
        if (map.find(val) != map.end()) return false;
        arr.emplace_back(val);
        // 记录 val 在动态数组中的位置
        map.emplace(val, arr.size() - 1);
        return true;
    }

    bool remove(int val) {
        if (map.find(val) == map.end()) return false;
        // 更新原来末尾元素的新位置
        map[arr[arr.size() - 1]] = map[val];
        // 与最后一个元素互换位置,然后删掉动态数组的末尾
        swap(arr[arr.size() - 1], arr[map[val]]);
        arr.pop_back();
        map.erase(val);
        return true;
    }

    int getRandom() {
        return arr[rand() % arr.size()];
    }
};

381. O(1) 时间插入、删除和获取随机元素 - 允许重复

  • set 记录相同元素所在的位置
#include <vector>
#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <unordered_set>

using namespace std;

class RandomizedCollection {
public:
    vector<int> arr;
    // <val, 在动态数组中下标的集合>
    unordered_map<int, unordered_set<int>> map;

    RandomizedCollection() {
    }

    bool insert(int val) {
        arr.emplace_back(val);
        // 记录 val 在动态数组中的位置
        map[val].emplace(arr.size() - 1);
        return map[val].size() == 1;
    }

    bool remove(int val) {
        if (map.find(val) == map.end()) return false;
        if (val == arr[arr.size() - 1]) {
            map[val].erase(arr.size() - 1);
            arr.pop_back();
        } else {
            // 从所有值为 val 的元素中选一个作为被删除元素
            int valIndex = *map[val].begin();
            // 数组末尾元素,用于放到被删除的位置
            int lastIndex = arr.size() - 1;
            int last = arr[lastIndex];

            // 1. 交换这两个元素在 map 中的定位信息
            // 先更新被删除元素的位置::val 由 valIndex 移动到 arr.size() - 1
            map[val].erase(valIndex);
            map[val].emplace(lastIndex);
            // 后更新 last 元素的位置:last 由 arr.size() - 1 移动到 valIndex
            map[last].erase(lastIndex);
            map[last].emplace(valIndex);

            // 2. 交换在数组中的位置,然后删掉末尾
            swap(arr[valIndex], arr[lastIndex]);
            map[val].erase(lastIndex);
            arr.pop_back();
        }
        // 移除空的集合
        if (map[val].size() == 0) map.erase(val);
        return true;
    }

    int getRandom() {
        return arr[rand() % arr.size()];
    }
};

295. 数据流的中位数

#include <vector>
#include <iostream>
#include <algorithm>
#include <queue>


using namespace std;

class MedianFinder {
public:
    // 左侧的大根堆,如果总个数为奇数个,就把中位数放到大根堆里
    priority_queue<int, vector<int>, less<int>> maxHeap;
    // 右侧的小根堆
    priority_queue<int, vector<int>, greater<int>> minHeap;

    MedianFinder() {

    }

    void addNum(int num) {
        if (maxHeap.size() == 0) {
            maxHeap.emplace(num);
            return;
        }
        if ((maxHeap.size() + minHeap.size()) & 1) {
            // 总个数为奇数个
            if (num <= maxHeap.top()) {
                // 放入左侧的大根堆
                maxHeap.emplace(num);
                // 把大根堆堆顶移到小根堆里,使两个堆的元素一样多
                minHeap.emplace(maxHeap.top());
                maxHeap.pop();
            } else {
                // 直接放入小根堆
                minHeap.emplace(num);
            }
        } else {
            // 总个数为偶数个
            if (num <= maxHeap.top()) {
                // 直接放入左侧的大根堆
                maxHeap.emplace(num);
            } else {
                // 放入小根堆
                minHeap.emplace(num);
                // 把小根堆堆顶移到大根堆里,使两个堆的元素一样多
                maxHeap.emplace(minHeap.top());
                minHeap.pop();
            }
        }
    }

    double findMedian() {
        if ((maxHeap.size() + minHeap.size()) & 1) {
            // 总个数为奇数个
            return maxHeap.top();
        } else {
            // 总个数为偶数个
            return (maxHeap.top() + minHeap.top()) / 2.0;
        }
    }
};

895. 最大频率栈

#include <vector>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <unordered_map>

using namespace std;

class FreqStack {
public:
    // <i, i 出现的次数>
    unordered_map<int, int> freq;
    // <出现的次数,包含出现这种次数的所有数的列表>
    unordered_map<int, vector<int>> countValues;
    // 最大次数
    int _max;

    FreqStack() {

    }

    void push(int val) {
        freq[val]++;
        // 如果没有对应次数的列表,就新建
        if (countValues.find(freq[val]) == countValues.end())
            countValues.emplace(freq[val], vector<int>());
        // 往这种次数对应的列表末尾加入当前数
        countValues[freq[val]].emplace_back(val);
        // 更新最大出现次数
        _max = max(_max, freq[val]);
    }

    int pop() {
        // 获取出现次数最大的列表的最后一个数,也就是最靠近栈顶的
        int res = countValues[_max].back();
        countValues[_max].pop_back();
        // 如果这个列表空了,就移除,并且出现的最大次数减一
        if (countValues[_max].empty())
            countValues.erase(_max--);
        // 出栈,并减少这个数字出现的次数
        if (freq[res] == 1)
            freq.erase(res);
        else
            freq[res]--;
        return res;
    }
};

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

#include <vector>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <string>
#include <unordered_map>
#include <unordered_set>

using namespace std;

class AllOne {
public:
    // 双向链表
    struct ListNode {
        int times;
        unordered_set<string> bucket;
        ListNode *prev;
        ListNode *next;

        ListNode() {
            prev = nullptr;
            next = nullptr;
        }

        ListNode(int times, string key) : ListNode() {
            this->times = times;
            bucket.emplace(key);
        }
    };

    // <val, address> 记录值 val 所在链表节点的地址
    unordered_map<string, ListNode *> map;
    ListNode *dummyHead;
    ListNode *dummyTail;

    // 在 cur 后面插入
    void insertNode(ListNode *pos, ListNode *node) {
        node->prev = pos;
        node->next = pos->next;
        pos->next->prev = node;
        pos->next = node;
    }

    void removeNode(ListNode *node) {
        node->next->prev = node->prev;
        node->prev->next = node->next;
        delete node;
        node = nullptr;
    }

    AllOne() {
        dummyHead = new ListNode();
        dummyTail = new ListNode();
        dummyHead->next = dummyTail;
        dummyTail->prev = dummyHead;
        dummyHead->times = 0;
        dummyTail->times = INT_MAX;
    }

    void inc(string key) {
        if (map.find(key) == map.end()) {
            // key 首次加入
            if (dummyHead->next->times == 1) {
                // 如果有记录词频为 1 的桶,就放入
                dummyHead->next->bucket.emplace(key);
                map[key] = dummyHead->next;
            } else {
                // 否则就新建桶并放入
                ListNode *node = new ListNode(1, key);
                map[key] = node;
                insertNode(dummyHead, node);
            }
        } else {
            // 不是首次加入,就移动到下个词频(当前词频加一)的桶中
            ListNode *cur = map[key];
            if (cur->next->times == cur->times + 1) {
                // 如果存在下个一个词频的桶,就移进去
                cur->next->bucket.emplace(key);
                map[key] = cur->next;
            } else {
                // 否则就新建桶并放入
                ListNode *node = new ListNode(cur->times + 1, key);
                map[key] = node;
                insertNode(cur, node);
            }
            // 从原来的桶里移除
            cur->bucket.erase(key);
            if (cur->bucket.empty()) removeNode(cur);
        }
    }

    void dec(string key) {
        ListNode *cur = map[key];
        if (cur->times == 1) {
            map.erase(key);
        } else {
            if (cur->prev->times == cur->times - 1) {
                // 移动到上个词频(当前词频减一)的桶中
                cur->prev->bucket.emplace(key);
                map[key] = cur->prev;
            } else {
                // 否则就新建桶并放入
                ListNode *node = new ListNode(cur->times - 1, key);
                map[key] = node;
                insertNode(cur->prev, node);
            }
        }
        // 从桶里移除
        cur->bucket.erase(key);
        if (cur->bucket.empty()) removeNode(cur);
    }

    string getMaxKey() {
        if (dummyTail->prev == dummyHead) return "";
        return *(dummyTail->prev->bucket.begin());
    }

    string getMinKey() {
        if (dummyHead->next == dummyTail) return "";
        return *(dummyHead->next->bucket.begin());
    }
};

标签:node,map,include,ListNode,val,key,设计,数据结构
From: https://www.cnblogs.com/sprinining/p/18438260

相关文章

  • 学期2024-2025-1 学号20241401《计算机基础与程序设计》第一周学习总结
    班级的链接2024计算机基础与程序设计作业要求的链接第一周作业作业的目标1、参考教程安装Linux系统;2、快速浏览一遍教材计算机科学概论(第七版),课本每章提出至少一个自己不懂的或最想解决的问题并在期末回答这些问题作业正文本博客教材学习内容总结快速浏览......
  • B端管理系统新手指引设计,一定要消除用户的畏惧心理
    管理系统的新手指引是为了帮助用户快速了解和熟悉系统的使用方法和功能,以便用户能够顺利地进行操作和管理。大千UI工场为大家分享几点经验:简单明了的介绍:在新手指引的开始,对系统进行简单明了的介绍,包括系统的名称、主要功能和使用场景等。让用户对系统有一个初步的了解。......
  • 2024-2025全网最全计算机软件毕业设计选题大全:不要踩坑了✅
    博主介绍:✌全网粉丝60W+,csdn特邀作者、Java领域优质创作者、csdn/掘金/哔哩哔哩/知乎/道客/小红书等平台优质作者,计算机毕设实战导师,目前专注于大学生项目实战开发,讲解,毕业答疑辅导,欢迎高校老师/同行前辈交流合作✌技术栈范围:SpringBoot、Vue、SSM、Jsp、HLMT、Nodejs......
  • 数据库课程设计案例:在线图书管理系统
    一、项目背景随着信息技术的迅猛发展,传统图书管理模式已逐渐无法满足现代图书馆的需求。在线图书管理系统应运而生,旨在为读者提供更方便快捷的图书查询、借阅和归还服务,同时帮助管理员高效管理书籍信息。二、系统功能需求用户管理用户注册与登录用户信息修改用户角色管理(......
  • 数据库课程设计案例:在线教育管理系统
    一、项目背景随着在线教育的兴起,传统的教学管理模式面临着新的挑战。在线教育管理系统旨在为学生、教师和管理员提供一个高效、便捷的学习与管理平台,以提升学习效果和管理效率。二、系统功能需求用户管理用户注册与登录角色管理(学生、教师、管理员)用户信息修改课程管理......
  • FastReport报表设计(仔细看)
    FastReport报表设计  2011-06-1616:56:19|  分类: 系统开发|举报|字号 订阅        下载LOFTER我的照片书  |  目录5.1前言5.2基本概念及操作5.3报表设计与范例5.4常用功能及函数5.5报表设计常用技巧5.1前言汽车业务管理系......
  • 算法训练营第三天| 203.移除链表元素、707.设计链表、206.反转链表
    203.移除链表元素状态:完成个人思路:首先令head符合条件,之后判断这个head是否为空,空的话返回空节点;非空的话继续进行。令pre=head;cur=head->next,只要cur非空,就判断cur的值的情况,如果需要删除,就改变pre->next和cur;如果不需要删除就继续检查下一个。看完讲解视频之后的想法:我......
  • springboot基于java的酒店管理系统设计与实现(源码+文档+调试+vue+前后端分离)
    收藏关注不迷路!!......
  • DCDC电源设计工具(软件)(一)—— WEBENCH(TI)
    目录一、简介二、在线链接三、设计界面介绍1、首界面2、芯片选择或芯片选型界面3、根据参数选择芯片及设计(1)参数输入界面(2)芯片选型界面(3)根据具体芯片型号选择设计   ①、芯片选择及参数输入界面        ②、TPS54331电源设计详情四、验证设计五、软......
  • [场景设计]断点续传
    要实现大文件的断点续传,通常的实现方式是将文件分块上传(切割文件)并记录每个块的状态,以便在中断后可以从上次上传完成的块继续上传。你可以基于以下几个步骤来实现这个功能,主要涉及字节流操作、文件分块、状态记录和续传的逻辑。1.文件分块将大文件切割成多个小块进行上传,这样在......