Design
//hash表 + 双向链表(头代表最新,尾代表老)
function ListNode(key, value) {
this.key = key
this.value = value
this.next = null
this.prev = null
}
var LRUCache = function (capacity) {
// 缓存容量
this.capacity = capacity
// 哈希表 key -> ListNode
this.hashTable = {}
// 缓存数目
this.count = 0
// 虚拟头尾
this.dummyHead = new ListNode()
this.dummyTail = new ListNode()
this.dummyHead.next = this.dummyTail
this.dummyTail.prev = this.dummyHead
}
//若哈希表中没有对应值,返回-1。若存在节点,刷新它的位置,移动到链表头部,返回该节点值
LRUCache.prototype.get = function (key) {
const node = this.hashTable[key]
if (!node) return -1
this.moveToHead(node)
return node.value
}
LRUCache.prototype.moveToHead = function (node) {
//从链表中删除该节点
this.removeFromList(node)
//将该节点添加到链表的头部
this.addToHead(node)
}
LRUCache.prototype.removeFromList = function (node) {
const prev = node.prev
const next = node.next
prev.next = next
next.prev = prev
}
LRUCache.prototype.addToHead = function (node) {
//插入到虚拟头结点和真实头结点之间,注意顺序,先链接node,再调整指针
//node的prev指针指向虚拟头结点
node.prev = this.dummyHead
//node的next指针指向原来的真实头结点
node.next = this.dummyHead.next
//原来的真实头结点的prev指向node
this.dummyHead.next.prev = node
//虚拟头结点的next指向node
this.dummyHead.next = node
}
//对于新数据,创建新节点,存入哈希表,并添加到链表头部(最不优先被淘汰),检查是否超容,决定是否剔除"老家伙"
//对于已有数据,更新数据值,刷新节点位置
LRUCache.prototype.put = function (key, value) {
const node = this.hashTable[key]
//insert
if (!node) {
const newNode = new ListNode(key, value)
this.hashTable[key] = newNode
this.addToHead(newNode)
this.count++
//check capacity
if (this.count > this.capacity) {
//删除"老家伙",将它从链表尾部删除
const tailNode = this.dummyTail.prev
this.removeFromList(tailNode)
delete this.hashTable[tailNode.key]
this.count--
}
//update
} else {
node.value = value
this.moveToHead(node)
}
}
//使用辅助栈
var MinStack = function () {
this.stack = []
//add an initial value
this.minStack = [Infinity]
}
//辅助栈同步放每次最小值
MinStack.prototype.push = function (x) {
this.stack.push(x)
this.minStack.push(Math.min(this.minStack[this.minStack.length - 1], x))
}
//同步pop
MinStack.prototype.pop = function () {
this.stack.pop()
this.minStack.pop()
}
MinStack.prototype.top = function () {
return this.stack[this.stack.length - 1]
}
MinStack.prototype.getMin = function () {
const val = this.minStack[this.minStack.length - 1]
return val === Infinity ? void 0 : val
}
//O(n) - O(1)
var MinStack = function () {
this.stack = []
this.minV = Number.MAX_VALUE
}
MinStack.prototype.push = function (val) {
const minV = this.minV
// update this.minV
if (val < this.minV) this.minV = val
//存的是真实值与min的差
//若当次push的是小值则存的负数
return this.stack.push(val - minV)
}
MinStack.prototype.pop = function () {
const item = this.stack.pop()
const minV = this.minV
//如果栈顶元素小于0,说明栈顶是当前最小的元素,它出栈会对this.minV造成影响,需更新this.minV
//上一个最小的是"minV - 栈顶元素",我们需要将上一个最小值更新为当前的最小值
//因为栈顶元素入栈的时候的通过 栈顶元素 = 真实值 - 上一个最小的元素 得到的
//而真实值 = minV, 可得出上一个最小的元素 = 真实值 - 栈顶元素
if (item < 0) {
this.minV = minV - item
return minV
}
return item + minV
}
MinStack.prototype.top = function () {
const item = this.stack[this.stack.length - 1]
const minV = this.minV
if (item < 0) return minV
//top时候需要对数据还原,这里注意是"上一个"最小值
return item + minV
}
MinStack.prototype.min = function () {
return this.minV
}
var TrieNode = function () {
//next[i]保存着下一个字符i的节点引用
this.next = {}
//当前节点是否可以作为一个单词的结束位置
this.isEnd = false
}
var Trie = function () {
this.root = new TrieNode()
}
Trie.prototype.insert = function (word) {
if (!word) return false
let node = this.root
for (let i = 0; i < word.length; i++) {
if (!node.next[word[i]]) {
node.next[word[i]] = new TrieNode()
}
node = node.next[word[i]]
}
node.isEnd = true
return true
}
Trie.prototype.search = function (word) {
if (!word) return false
let node = this.root
for (let i = 0; i < word.length; i++) {
if (node.next[word[i]]) {
node = node.next[word[i]]
} else {
return false
}
}
return node.isEnd
}
Trie.prototype.startsWith = function (prefix) {
if (!prefix) return true
let node = this.root
for (let i = 0; i < prefix.length; i++) {
if (node.next[prefix[i]]) {
node = node.next[prefix[i]]
} else {
return false
}
}
return true
}
var MyStack = function () {
this.queue = []
}
MyStack.prototype.push = function (x) {
this.queue[this.queue.length] = x
}
MyStack.prototype.pop = function () {
if (this.empty()) return undefined
const popItem = this.queue[this.queue.length - 1]
this.queue.length = this.queue.length - 1
return popItem
}
MyStack.prototype.top = function () {
return this.queue[this.queue.length - 1]
}
MyStack.prototype.empty = function () {
return this.queue.length === 0
}
var MyQueue = function () {
this.inStack = []
this.outStack = []
}
MyQueue.prototype.push = function (x) {
this.inStack.push(x)
}
//返回的是outStack,所以需先反向装一下
MyQueue.prototype.pop = function () {
if (!this.outStack.length) this.in2out()
return this.outStack.pop()
}
//返回的是outStack,所以需先反向装一下
MyQueue.prototype.peek = function () {
if (!this.outStack.length) this.in2out()
return this.outStack[this.outStack.length - 1]
}
MyQueue.prototype.empty = function () {
return this.outStack.length === 0 && this.inStack.length === 0
}
MyQueue.prototype.in2out = function () {
while (this.inStack.length) {
this.outStack.push(this.inStack.pop())
}
}
var MyCircularDeque = function (k) {
//point to first valid position
this.front = 0
//point to last valid position
this.rear = 0
this.capacity = k + 1
this.arr = Array(this.capacity)
}
MyCircularDeque.prototype.insertFront = function (value) {
if (this.isFull()) return false
this.front = (this.front - 1 + this.capacity) % this.capacity
this.arr[this.front] = value
return true
}
MyCircularDeque.prototype.insertLast = function (value) {
if (this.isFull()) {
return false
}
this.arr[this.rear] = value
this.rear = (this.rear + 1) % this.capacity
return true
}
MyCircularDeque.prototype.deleteFront = function () {
if (this.isEmpty()) {
return false
}
// front 被设计在数组的开头,所以是 +1
this.front = (this.front + 1) % this.capacity
return true
}
MyCircularDeque.prototype.deleteLast = function () {
if (this.isEmpty()) {
return false
}
// rear 被设计在数组的末尾,所以是 -1
this.rear = (this.rear - 1 + this.capacity) % this.capacity
return true
}
MyCircularDeque.prototype.getFront = function () {
if (this.isEmpty()) {
return -1
}
return this.arr[this.front]
}
MyCircularDeque.prototype.getRear = function () {
if (this.isEmpty()) {
return -1
}
// 当 rear 为 0 时防止数组越界
return this.arr[(this.rear - 1 + this.capacity) % this.capacity]
}
MyCircularDeque.prototype.isEmpty = function () {
return this.front === this.rear
}
MyCircularDeque.prototype.isFull = function () {
// 注意:这个设计是非常经典的做法
return (this.rear + 1) % this.capacity == this.front
}
/**
* Your MyCircularDeque object will be instantiated and called as such:
* var obj = new MyCircularDeque(k)
* var param_1 = obj.insertFront(value)
* var param_2 = obj.insertLast(value)
* var param_3 = obj.deleteFront()
* var param_4 = obj.deleteLast()
* var param_5 = obj.getFront()
* var param_6 = obj.getRear()
* var param_7 = obj.isEmpty()
* var param_8 = obj.isFull()
*/
var MyLinkedList = function () {
this.size = 0
this.head = new ListNode(0)
}
MyLinkedList.prototype.get = function (index) {
if (index < 0 || index >= this.size) return -1
let cur = this.head
while (index-- >= 0) cur = cur.next
return cur.val
}
MyLinkedList.prototype.addAtHead = function (val) {
this.addAtIndex(0, val)
}
MyLinkedList.prototype.addAtTail = function (val) {
this.addAtIndex(this.size, val)
}
MyLinkedList.prototype.addAtIndex = function (index, val) {
if (index > this.size) return
index = Math.max(0, index)
this.size++
let prev = this.head
while (index-- > 0) prev = prev.next
let newAdd = new ListNode(val)
newAdd.next = prev.next
prev.next = newAdd
}
MyLinkedList.prototype.deleteAtIndex = function (index) {
if (index < 0 || index >= this.size) return
this.size--
let prev = this.head
while (index-- > 0) prev = prev.next
prev.next = prev.next.next
}
Last updated