摘要:首先要做到是,能想到的數(shù)據(jù)結(jié)構(gòu)只有兩三種,一個(gè)是,一個(gè)是,是,還有一個(gè),是。不太可能,因?yàn)殚L(zhǎng)度要而且不可變,題目也沒(méi)說(shuō)長(zhǎng)度固定??梢宰龅胶投际恰R?yàn)檫€有函數(shù),要可以,所以還需要一個(gè)數(shù)據(jù)結(jié)構(gòu)來(lái)記錄順序,自然想到。
LRU Cache
題目鏈接:https://leetcode.com/problems...
這個(gè)題要求O(1)的復(fù)雜度。首先要做到get(key)是O(1),能想到的數(shù)據(jù)結(jié)構(gòu)只有兩三種,一個(gè)是HashMap
public class LRUCache { class ListNode { ListNode prev; ListNode next; int val = 0; int key = 0; ListNode() {} ListNode(int key, int val) { this.key = key; this.val = val; } } // new node(most recently) add to the tail part public void append(ListNode node) { node.prev = tail.prev; tail.prev.next = node; node.next = tail; tail.prev = node; } // least recently node need to be remove from head public void remove() { remove(head.next); } // remove the certain node public void remove(ListNode node) { node.prev.next = node.next; node.next.prev = node.prev; } ListNode head, tail; MapLFU Cachemap; int remain; public LRUCache(int capacity) { remain = capacity; // map for get map = new HashMap(); // list for put head = new ListNode(); tail = new ListNode(); head.next = tail; tail.prev = head; } public int get(int key) { if(map.containsKey(key)) { // remove the key node to the tail int value = map.get(key).val; put(key, value); return value; } else return -1; } public void put(int key, int value) { if(map.containsKey(key)) { ListNode node = map.get(key); node.val = value; remove(node); append(node); } else { // not contain, check if count > capacity // remove the least recent node in list & map if(remain == 0) { map.remove(head.next.key); remove(); remain++; } ListNode node = new ListNode(key, value); append(node); map.put(key, node); remain--; } } } /** * Your LRUCache object will be instantiated and called as such: * LRUCache obj = new LRUCache(capacity); * int param_1 = obj.get(key); * obj.put(key,value); */
題目鏈接:https://leetcode.com/problems...
上一題是只考慮出現(xiàn)的時(shí)間,這題加了frequency。那么再加一個(gè)map存freq應(yīng)該是可行的?,F(xiàn)在node除了要保存順序還得保存freq,感覺(jué)上像是個(gè)二維的,先按freq排序再考慮出現(xiàn)順序。每次得保存下這個(gè)freq出現(xiàn)最早的值,再出現(xiàn)的時(shí)候,要從這freq里刪了,移到下一個(gè)freq的tail上。想了下感覺(jué)還是不太好做,看了網(wǎng)上的答案。
參考這個(gè)博客:
http://bookshadow.com/weblog/...
first -> point to the freqNode with freq = 1
Map
relation between freqNode:
first(freq 0) <-> freq 1 <-> freq 2 <-> ......
Map
get(key):
case 1: return -1
case 2: exist =>
find keyNode and remove from freqNode, if cur freqNode has no element, remove freqNode
find freqNode through freqMap,
find next freqNode(freq + 1) through freqNode,
add keyNode to the tail of next freqNode
put(key, value)
case 1: not exist in keyMap => add to the tail of freqNode with freq = 1
case 2: exist =>
find keyNode, set value and remove from freqNode, if cur freqNode has no element, remove freqNode
find freqNode through freqMap,
find next freqNode(freq + 1) through freqNode,
add keyNode to the tail of next freqNode
其中,keyNode和keyMap和上一題一樣都是可以用LinkedHashMap來(lái)實(shí)現(xiàn)的。那么這里可以稍微改一下,把keyMap里面直接放
public class LFUCache { class freqNode { int freq = 0; freqNode prev, next; // store keys LinkedHashSetkeyNodes = new LinkedHashSet(); freqNode() {} freqNode(int freq) { this.freq = freq; } public int delete() { // if(keyNodes.isEmpty()) return; int key = keyNodes.iterator().next(); keyNodes.remove(key); return key; } public void delete(int key) { // if(!keyNodes.contains(key)) return; keyNodes.remove(key); } public void append(int key) { keyNodes.add(key); } } int remain; // key, freqNode pair Map freqMap; // key, value pair Map keyMap; freqNode first; freqNode last; public LFUCache(int capacity) { this.remain = capacity; freqMap = new HashMap(); keyMap = new HashMap(); first = new freqNode(); last = new freqNode(); first.next = last; last.next = first; } public int get(int key) { if(!keyMap.containsKey(key)) return -1; else { updateFreq(key); return keyMap.get(key); } } public void put(int key, int value) { if(!keyMap.containsKey(key)) { if(remain == 0) { if(first.next.freq == 0) return; // remove the least frequent int del = first.next.delete(); keyMap.remove(del); freqMap.remove(del); remain++; } // update map and add node keyMap.put(key, value); update(first, key); remain--; } else { updateFreq(key); keyMap.put(key, value); } } private void updateFreq(int key) { freqNode node = freqMap.get(key); update(node, key); // remove current node if has no keyNodes node.delete(key); if(node.keyNodes.size() == 0) { removeNode(node); } } private void update(freqNode node, int key) { // append to the next freq addAfterNode(node); node.next.append(key); // update freqMap key with next freqNode freqMap.put(key, node.next); } private void addAfterNode(freqNode node) { if(node.next.freq != node.freq + 1) { freqNode newNode = new freqNode(node.freq + 1); freqNode temp = node.next; node.next = newNode; newNode.prev = node; temp.prev = newNode; newNode.next = temp; node = null; } } private void removeNode(freqNode node) { node.prev.next = node.next; node.next.prev = node.prev; } } /** * Your LFUCache object will be instantiated and called as such: * LFUCache obj = new LFUCache(capacity); * int param_1 = obj.get(key); * obj.put(key,value); */
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/66567.html
摘要:在靜態(tài)的頻率分布下,性能也落后于因?yàn)槠洳辉贋椴辉诰彺嬷械臄?shù)據(jù)維護(hù)任何頻率數(shù)據(jù)??梢栽斠?jiàn)的準(zhǔn)入淘汰策略是新增一個(gè)新的元素時(shí),判斷使用該元素替換一個(gè)舊元素,是否可以提升緩存命中率。 1. Introduction LFU的局限: LFU實(shí)現(xiàn)需要維護(hù)大而復(fù)雜的元數(shù)據(jù)(頻次統(tǒng)計(jì)數(shù)據(jù)等) 大多數(shù)實(shí)際工作負(fù)載中,訪問(wèn)頻率隨著時(shí)間的推移而發(fā)生根本變化(這是外賣業(yè)務(wù)不適合樸素LFU的根本原因) 針...
摘要:在靜態(tài)的頻率分布下,性能也落后于因?yàn)槠洳辉贋椴辉诰彺嬷械臄?shù)據(jù)維護(hù)任何頻率數(shù)據(jù)??梢栽斠?jiàn)的準(zhǔn)入淘汰策略是新增一個(gè)新的元素時(shí),判斷使用該元素替換一個(gè)舊元素,是否可以提升緩存命中率。 1. Introduction LFU的局限: LFU實(shí)現(xiàn)需要維護(hù)大而復(fù)雜的元數(shù)據(jù)(頻次統(tǒng)計(jì)數(shù)據(jù)等) 大多數(shù)實(shí)際工作負(fù)載中,訪問(wèn)頻率隨著時(shí)間的推移而發(fā)生根本變化(這是外賣業(yè)務(wù)不適合樸素LFU的根本原因) 針...
摘要:如果每一個(gè)頻率放在一個(gè)里面,每個(gè)也有頭尾兩個(gè)指針,指向相鄰的。實(shí)際上相鄰的可以由的第一可以由的最后一個(gè)唯一確認(rèn)。也就是說(shuō),在的設(shè)計(jì)基礎(chǔ)上。也就是說(shuō)頻率為的點(diǎn),指向的下一個(gè)是頻率為的點(diǎn)移除和一樣。里存在的點(diǎn),加到尾部的后一個(gè)。 只個(gè)代碼由LRU改進(jìn)得到。如果每一個(gè)頻率放在一個(gè)LRU里面,每個(gè)LRU也有頭尾兩個(gè)指針,指向相鄰的LRU。實(shí)際上相鄰的LRU可以由frequency = t+1的...
摘要:緩存算法我是,我會(huì)統(tǒng)計(jì)每一個(gè)緩存數(shù)據(jù)的使用頻率,我會(huì)把使用最少的緩存替換出緩存區(qū)。瀏覽器就是使用了我作為緩存算法。在緩存系統(tǒng)中找出最少最近的對(duì)象是需要較高的時(shí)空成本。再來(lái)一次機(jī)會(huì)的緩存算法,是對(duì)的優(yōu)化。直到新的緩存對(duì)象被放入。 緩存 什么是緩存? showImg(https://segmentfault.com/img/bVusZg); 存貯數(shù)據(jù)(使用頻繁的數(shù)據(jù))的臨時(shí)地方,因?yàn)槿≡?..
閱讀 3311·2023-04-25 22:47
閱讀 3822·2021-10-11 10:59
閱讀 2335·2021-09-07 10:12
閱讀 4308·2021-08-11 11:15
閱讀 3457·2019-08-30 13:15
閱讀 1774·2019-08-30 13:00
閱讀 996·2019-08-29 14:02
閱讀 1712·2019-08-26 13:57