Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
编程世界总是离不了算法
最近在看框架源码时,会有很多算法的实现逻辑,有时候会感到吃力
于是决定蹭着假期,加强算法和数据结构相关的知识
那怎么提升呢?
其实我知道算法这东西没有捷径,多写多练才能提升,于是我开启我的LeetCode刷题之旅
第一阶段目标是:200道,每天1到2篇
为了不乱,本系列文章目录分为三部分:
- 今日题目:xxx
- 我的思路
- 代码实现
今天题目: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 : ''
};
总结
实现方式其实有很多,这里仅供参考~
由于刚开始刷题,也不知道从哪里刷好,如果前辈们有好的建议,希望不吝赐教,感谢🌹