开启我的LeetCode刷题日记:432. 全 O(1) 的数据结构

139 阅读3分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

编程世界总是离不了算法

最近在看框架源码时,会有很多算法的实现逻辑,有时候会感到吃力

于是决定蹭着假期,加强算法和数据结构相关的知识

那怎么提升呢?

其实我知道算法这东西没有捷径,多写多练才能提升,于是我开启我的LeetCode刷题之旅

第一阶段目标是:200道,每天12

为了不乱,本系列文章目录分为三部分:

  1. 今日题目:xxx
  2. 我的思路
  3. 代码实现

今天题目:432. 全 O(1) 的数据结构

请你设计一个用于存储字符串计数的数据结构,并能够返回计数最小和最大的字符串。

实现 AllOne 类:

AllOne() 初始化数据结构的对象。 inc(String key) 字符串 key 的计数增加 1 。如果数据结构中尚不存在 key ,那么插入计数为 1 的 key 。 dec(String key) 字符串 key 的计数减少 1 。如果 key 的计数在减少后为 0 ,那么需要将这个 key 从数据结构中删除。测试用例保证:在减少计数前,key 存在于数据结构中。 getMaxKey() 返回任意一个计数最大的字符串。如果没有元素存在,返回一个空字符串 "" 。 getMinKey() 返回任意一个计数最小的字符串。如果没有元素存在,返回一个空字符串 "" 。  

示例:

输入 ["AllOne", "inc", "inc", "getMaxKey", "getMinKey", "inc", "getMaxKey", "getMinKey"] [[], ["hello"], ["hello"], [], [], ["leet"], [], []] 输出 [null, null, null, "hello", "hello", null, "hello", "leet"]

解释 AllOne allOne = new AllOne(); allOne.inc("hello"); allOne.inc("hello"); allOne.getMaxKey(); // 返回 "hello" allOne.getMinKey(); // 返回 "hello" allOne.inc("leet"); allOne.getMaxKey(); // 返回 "hello" allOne.getMinKey(); // 返回 "leet"  

提示:

1 <= key.length <= 10 key 由小写英文字母组成 测试用例保证:在每次调用 dec 时,数据结构中总存在 key 最多调用 inc、dec、getMaxKey 和 getMinKey 方法 5 * 104 次

我的思路

要实现O(1)查找到最大最小值,那么考虑维护一个有序列表,列表的第一项就是最小值的节点,列表的最后一项就是最大值的节点,这样查找就没问题了。要实现inc和dec的O(1),就用到了链表的优势,天然在删除和新增O(1), 所以最终是要维护一个有序的链表。 删除链表节点很容易, 插入链表节点就需要考虑在什么位置插入,插在左边还是右边。所以记录了每一层的头尾节点来找位置。

代码实现

var AllOne = function() {
    this.first = this.last = null
    this.lvHead = {} // 每层头节点
    this.lvLast = {} // 每层尾节点
    this.data = {}
    
    this.remove = function(node) {
        let f = this.lvHead[node.val]
        let l = this.lvLast[node.val]
        
        // 从链表中删除
        if(node.prev) node.prev.next = node.next
        if(node.next) node.next.prev = node.prev
        
        // 维护头尾
        node == this.first ? this.first = node.next : ''
        node == this.last  ? this.last  = node.prev : ''
        
        // 维护每一层头尾
        if(f == l) this.lvHead[node.val] = this.lvLast[node.val] = null
        else if (f == node) this.lvHead[node.val] = node.next
        else if (l == node) this.lvLast[node.val] = node.prev
        
    }
    
    // 在pos位置上的type方向上插入node节点
    // type==0表示左边, type==1表示右边
    this.add = function(pos, type, node) {
        
        let f = this.lvHead[node.val]
        let l = this.lvLast[node.val]
        
        if(pos == null) {
            if(!this.first) {
                this.first = this.last = node
                this.lvLast[node.val] = this.lvHead[node.val] = node
            } else {
                let f = this.first
                node.next = f
                f.prev = node
                this.first = node
                this.lvHead[node.val] = node
            }
            return
        }
        
        if(type == 1) {
            let next = pos.next
            node.next = next
            node.prev = pos
            pos.next = node
            next ? next.prev = node : ''
            
            if (f == null) {
              this.lvHead[node.val] = this.lvLast[node.val] = node
            } else {
              this.lvHead[node.val] = node   
            } 
            pos == this.last ? this.last = node : ''
        } else if(type == 0) {
            let prev = pos.prev
            node.next = pos
            node.prev = prev
            pos.prev = node
            prev ? prev.next = node : ''
            
            if (l == null) {
              this.lvHead[node.val] = this.lvLast[node.val] = node
            } else {
              this.lvLast[node.val] = node   
            } 
            pos == this.first ? this.first = node : ''
        }
    }
};

AllOne.prototype.inc = function(key) {
    let node = null
    if(!this.data[key]) {
        this.data[key] = node = {key:key, val: 1, next: null, prev: null}
        this.add(null, 1, node)
    } else {
        node = this.data[key]
        let newNode = {key:key, val: node.val + 1, next: null, prev: null}
        this.data[key] = newNode
        this.add(this.lvLast[node.val], 1, newNode)
        this.remove(node)
        this.data[key] = newNode
    }
};


AllOne.prototype.dec = function(key) {
    if(!this.data[key]) {
        return
    } else {
        let node = this.data[key]
        let newNode = {key:key, val: node.val - 1, next: null, prev: null}
        if(newNode.val) {
            this.data[key] = newNode
            this.add(this.lvHead[node.val], 0,  newNode)
        } else {
            this.data[key] = null
        }
        this.remove(node)
    }
};

AllOne.prototype.getMaxKey = function() {
    return this.last ?  this.last.key : ''
};

AllOne.prototype.getMinKey = function() {
    return this.first ?  this.first.key : ''
};

总结

实现方式其实有很多,这里仅供参考~

由于刚开始刷题,也不知道从哪里刷好,如果前辈们有好的建议,希望不吝赐教,感谢🌹