纪念一下做出来的第一道leetCodeHard题目460.lfu缓存

58 阅读1分钟
/**
 * 实现节点
 * @param {*} k 
 * @param {*} v 
 */

class LinkedHashSet {
    constructor() {
      this.set = new Set();
      this.head = null;
      this.tail = null;
    }
  
    findFirstElement() {
        return this.head;
    }

    size() {
        let size = 0
        let current = this.head
        while (current !== null) {
            size+=1
            current = current.next;
          }
        return size
    }

    add(element) {
      if (!this.set.has(element)) {
        const entry = { element, prev: null, next: null };
  
        if (this.head === null) {
          this.head = entry;
          this.tail = entry;
        } else {
          this.tail.next = entry;
          entry.prev = this.tail;
          this.tail = entry;
        }
  
        this.set.add(element);
      }
    }
  
    delete(element) {
      if (this.set.has(element)) {
        const entry = this.findEntry(element);
  
        if (entry.prev) {
          entry.prev.next = entry.next;
        } else {
          this.head = entry.next;
        }
  
        if (entry.next) {
          entry.next.prev = entry.prev;
        } else {
          this.tail = entry.prev;
        }
  
        this.set.delete(element);
      }
    }
  
    has(element) {
      return this.set.has(element);
    }
  
    forEach(callback) {
      let current = this.head;
      while (current !== null) {
        callback(current.element);
        current = current.next;
      }
    }
  
    findEntry(element) {
      let current = this.head;
      while (current !== null) {
        if (current.element === element) {
          return current;
        }
        current = current.next;
      }
      return null;
    }
  
    toArray() {
      const result = [];
      this.forEach((element) => {
        result.push(element);
      });
      return result;
    }
  }
  const set = new LinkedHashSet();

let LFUCache = function (capacity) {
    this.keyToVal = new Map()
    this.keyToFreq = new Map()
    this.freqToKeys = new Map()
    this.cap = capacity
    this.minFreq = 0
}

LFUCache.prototype.increaseFreq = function(key) {
    console.log('------------增加Freq开始--------------')
    console.log(`增加key:${key}的freq`)
    // 获取keyToFreq中key对应的freq
    let freq = this.keyToFreq.get(key)
    console.log(`当前key:${key}的freq:${freq}`)
    // 设置keyToFreq中key对应的freq+1
    this.keyToFreq.set(key, freq+1)
    console.log(`设置keyToFreq中key:${key}对应的freq+1`, freq + 1)
    // 将freqToKey中的freq对应的列表中的当前key删除
    console.log(`keyToFreq:`, this.keyToFreq)
    console.log(`开始删除freqToKeys中freq:${freq}对应的列表中的key:${key}`)
    let flag = this.freqToKeys.has(freq)
    console.log('flag:', flag)
    if(flag) {
        console.log('flag:true中的freqToKeys', this.freqToKeys)
        this.freqToKeys.get(freq).delete(key)
    }
    console.log(`freqToKeys中的当前key:${key}删除结束`, this.freqToKeys)
    if(this.freqToKeys.get(freq + 1)) {
        this.freqToKeys.get(freq + 1).add(key)
        console.log(`如果当前freqToKeys有freq+1:${freq+1}的键, 直接将key放到数组`)
    } else {
        let a = new LinkedHashSet();
        a.add(key)
        console.log('aaa', a)
        this.freqToKeys.set(freq + 1, a) 
        console.log(`如果当前freqToKeys没有freq+1:${freq+1}的键, 则创建一个,并且直接将key放到数组`)
    }
    console.log('当前freqToKeys结构:', this.freqToKeys)

    // 如果这个freq对应的列表空了,则移除这个freq
    console.log(`this.freqToKeys.get(freq).size, freq:${freq}`, this.freqToKeys.get(freq).size())
    if(this.freqToKeys.get(freq).size()===0) {
        console.log(`this.freqToKeys`, this.freqToKeys)
        console.log('当前freq对应的列表空了,移除这个freq')
        this.freqToKeys.delete(freq)
        if(freq==this.minFreq) {
            this.minFreq++;
        }
    }
    console.log('最终的freqToKeys', this.freqToKeys)
}


LFUCache.prototype.removeMinFreqKey = function() {
    console.log('------------容量满了移除最小频率的key开始------------')
    console.log('当前freqToKeys-1-1-1-1', this.freqToKeys)
    let keyList = this.freqToKeys.get(this.minFreq)
    console.log('当前keyList: ', keyList)
    let deletedElement = keyList.findFirstElement()
    let deletedKey = deletedElement.element
    console.log('deletedElement:', deletedElement)
    keyList.delete(deletedKey)
    if(keyList.size===0) {
        this.freqToKeys.delete(this.minFreq)
    }
    console.log('设置freqToKeys开始00000', this.freqToKeys)
    this.keyToVal.delete(deletedKey)
    this.keyToFreq.delete(deletedKey)
    console.log('设置freqToKeys开始11111', this.freqToKeys)
}


LFUCache.prototype.get = function (key) {
    if (!this.keyToFreq.has(key)) {
        return -1;
    }
    this.increaseFreq(key)
    console.log(`取出KeyToVal中key:${key}的值`, this.keyToVal.get(key))
    return this.keyToVal.get(key)
}
LFUCache.prototype.put = function (key, val) {
    console.log(`-------------put开始-------------,key:${key}, val:${val}`)
    console.log('this.freqToKeys', this.freqToKeys)
    // 添加的时候如果容量小于0,则不添加
    if(this.cap <= 0) return;
    // 如果keyToVal的map中有了这个key
    if(this.keyToVal.has(key)) {
        // 更新keyToVal中的key对应的val
        this.keyToVal.set(key, val)
        // key对应的freq+1
        this.increaseFreq(key);
        return
    }
    // 如果容量已满,需要去掉freq最小的key
    if(this.cap<=this.keyToVal.size) {
        this.removeMinFreqKey()
    }
    
    // 设置keyToVal
    this.keyToVal.set(key, val)
    console.log('设置keyToVal', this.keyToVal)
    // 设置keyToFreq为1
    this.keyToFreq.set(key, 1)
    console.log(`设置KeyToFreq为1`, this.keyToFreq)

    // 设置freqToKey

    console.log('设置freqToKeys开始22222', this.freqToKeys)

    if(this.freqToKeys.get(1)) {
        console.log('1次push')
        this.freqToKeys.get(1).add(key)
    } else {
        console.log('没有push')
        this.freqToKeys.set(1, new LinkedHashSet())
        // 取出1对应的数组放入对应的key
        this.freqToKeys.get(1).add(key)
    }
    // this.freqToKeys.get(1).put()
    console.log('%设置freqToKeys的HashSet%', this.freqToKeys)
    // 插入新的Key之后最小的freq肯定是1
    this.minFreq = 1;
    console.log('设置minFreq为1')
}

let lfu = new LFUCache(2);
lfu.put(1, 3);   // cache=[1,_], cnt(1)=1
lfu.put(2, 4);   // cache=[2,1], cnt(2)=1, cnt(1)=1

console.log(lfu.get(1));      // 返回 1
                 // cache=[1,2], cnt(2)=1, cnt(1)=2
console.log('lfu.put(3, 3)----->')
lfu.put(3, 3);   // 去除键 2 ,因为 cnt(2)=1 ,使用计数最小
//                  // cache=[3,1], cnt(3)=1, cnt(1)=2
console.log('lfu.get(2)', lfu.get(2));      // 返回 -1(未找到)

console.log('lfu.get(3)', lfu.get(3));      // 返回 3
// // //                  // cache=[3,1], cnt(3)=2, cnt(1)=2
lfu.put(4, 4);   // 去除键 1 ,1 和 3 的 cnt 相同,但 1 最久未使用
//                  // cache=[4,3], cnt(4)=1, cnt(3)=2
console.log(`lfu.get(1)`, lfu.get(1));      // 返回 -1(未找到)
console.log(`lfu.get(3)`, lfu.get(3));      // 返回 3
// //                  // cache=[3,4], cnt(4)=1, cnt(3)=3
console.log(`lfu.get(4)`, lfu.get(4));      // 返回 4
//                  // cache=[3,4], cnt(4)=2, cnt(3)=3