LRU问题

相关:

学到的东西

  • 链表头加dummy结点方便删除操作
  • this.key = key; //前一个用this.是为了访问实例域,若不如此,key = key都是参数变量。(见java核心技术p126)
  • 在自己的class里可以直接访问自己的private变量,比如LRUCache构造方法中,可以直接给private变量count赋值。
  • Map api
    • map.containsKey(key)
    • map.get(key)
    • map.put(key,value)
    • map.remove(key)
    • 建立一个HashMap:
      • private Map<Integer,ListNode> map;
      • map = new HashMap<>();
  • 在牛客问题上学到了:

LRU Cache思路总览:以LC146为例

  • 数据结构的定义:

  • 双向链表形式,靠近头部->旧,靠近尾部->新

  • put方法:

  • 一切开始之前:先判断capacity是否正常!capacity<=0,直接返回!

    • put的结点key是否已经存在?(通过map.containsKey(key)快速查找)
      • 存在:更新value,视为内存使用,故将put进去的node转移到链表尾
        • 新node是不是链表尾?
          • 是:数据结构无需改变
          • 不是:需要转移node
      • 不存在:
        • 1.将新结点添加到链表尾
        • 2.Map中增加一对key-node对
        • 3.审核未加结点时链表长度是否<=capacity
          • 链表长度超过capacity:需要进行删头操作removeHead(),同时删除map中对应项
          • 链表长度未超过:计数器count++ 即可
  • get方法

  • 一切开始之前,先判断capacity是否正常!不正常就返回-1!

    • 结点是否在链表中?(map.containsKey(key))
      • 存在:那么结点是否在链表尾?(get视为一次内存使用,是否需要更新链表结构?)
        • 结点不在链表尾:那么需要把结点转移到链表尾,之后返回get到的value
        • 结点在链表尾:那么不需要更新链表,直接返回get到的value
      • 结点不在链表中:返回-1

LeetCode146问题的解答

我踩过的坑点:

  • 定义map:private Map<Integer,ListNode> map; //不要写成=map
  • removeHead中要记得把map中的项也删除
  • put时将已有结点转移到尾部,分为两步走:1.删除已有结点 2.结点插入到尾部
public class LRUCache{
        
         public class ListNode{
            int key;
            int val;
            ListNode prev;
            ListNode next;
             public ListNode(int key,int val){
                 this.key = key;
                 this.val = val;
             }
        }
        private int capacity;
        private int count;
        private ListNode dummy;
        private ListNode tail;
        private Map<Integer,ListNode> map;//ERROR1:不要写成=map
        public LRUCache(int capacity){
            this.capacity = capacity;
            count = 0;
            dummy = new ListNode(0,0);
            tail = dummy;
            map = new HashMap<>();
        }
        public void removeHead(){
            map.remove(dummy.next.key);//记住要删除表内的项!
            dummy.next = dummy.next.next;
            if(dummy.next!=null)  dummy.next.prev = dummy;
            else return;
        }
        public void appendTail(ListNode node){
            tail.next = node;
            node.prev = tail;
            node.next = null;
            tail = node;
        }
        
        public int get(int key){
            if(map.containsKey(key)){
                ListNode node = map.get(key);
                if(node!=tail){
                    node.prev.next = node.next;
                    node.next.prev = node.prev;
                    appendTail(node);
                    return node.val;
                }
                else{//node is tail
                    return node.val;
                }
            }
            else{
                return -1;
            }
        }
       
        public void put(int key,int value){
            if(map.containsKey(key)){
                ListNode node = map.get(key);
                node.val = value;/*NOTE:key相同,value不同,要更新value!!*/
                if(node != tail){
                    node.prev.next = node.next;
                    node.next.prev = node.prev;
                    appendTail(node);/*NOTE:要记得把node挪到尾部!*/
                }
                else return;
            }
            else{
                ListNode node = new ListNode(key,value);
                map.put(key,node);
                appendTail(node);
                if(count < capacity){
                    count++;
                }
                else{
                    removeHead();
                }
            }
        }
    }
/**
 * 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);
 */

牛客网LRU Cache问题的解答

我踩过的坑点:

  • 此题特性:put的结点,key和已有结点重复,更新value的情况,不算是访问缓存中的数据,从而不需要对链表进行操作。
  • 需要额外留意capacity<=0的情况,单独考虑此边界条件。不然会报空指针的错误。
/*链接:https://www.nowcoder.com/questionTerminal/3da4aeb1c76042f2bc70dbcb94513338
来源:牛客网
第一行读入一个整数n,表示LRU Cache的容量限制。 从第二行开始一直到文件末尾,每1行代表1个操作。
如果每行的第1个字符是p,则该字符后面会跟随2个整数,表示put操作的key和value。
如果每行的第1个字符是g,则该字符后面会跟随1个整数,表示get操作的key。
*/
 
import java.util.Scanner;
import java.util.Map;
import java.util.HashMap;
 
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int capacity = sc.nextInt();
        LRUCache cache = new LRUCache(capacity);
        while(sc.hasNextLine()){
            String input[] = sc.nextLine().trim().split(" ");
            if(input[0].equals("p")){
                int key = Integer.parseInt(input[1]);
                int val = Integer.parseInt(input[2]);
                cache.put(key,val);
            }
            else if(input[0].equals("g")){
                int key = Integer.parseInt(input[1]);
                System.out.println(cache.get(key));
            }
        }
        sc.close();
    }
     
public static class LRUCache{
         public class ListNode{
            int key;
            int val;
            ListNode prev;
            ListNode next;
             public ListNode(int key,int val){
                 this.key = key;
                 this.val = val;
             }
        }
        private int capacity;
        private int count;
        private ListNode dummy;
        private ListNode tail;
        private Map<Integer,ListNode> map;//ERROR1:不要写成=map
         
        public LRUCache(int capacity){
            this.capacity = capacity;
            count = 0;
            dummy = new ListNode(0,0);
            tail = dummy;
            map = new HashMap<>();
        }
     
        public void removeHead(){
            map.remove(dummy.next.key);//记住要删除表内的项!
            dummy.next = dummy.next.next;
            if(dummy.next!=null)  dummy.next.prev = dummy;
            else return;
        }
        public void appendTail(ListNode node){
            tail.next = node;
            node.prev = tail;
            node.next = null;
            tail = node;
        }
 
        public int get(int key){
            if (capacity <= 0)  return -1;
            if(map.containsKey(key)){
                ListNode node = map.get(key);
                if(node!=tail){
                    node.prev.next = node.next;
                    node.next.prev = node.prev;
                    appendTail(node);
                    return node.val;
                }
                else{//node is tail
                    return node.val;
                }
            }
            else{
                return -1;
            }
        }
 
        public void put(int key,int value){
            if (capacity <= 0)  return;
            if(map.containsKey(key)){
                ListNode node = map.get(key);
                node.val = value;//NOTE:key相同,value不同,要更新value!!
                //NOTE:此题特性:更新value不算使用,故链表结构不变
                return;
            }
            else{
                ListNode node = new ListNode(key,value);
                map.put(key,node);
                appendTail(node);
                if(count < capacity){
                    count++;
                }
                else{
                    removeHead();
                }
            }
        }
    }
     
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值