LeetCode之路2,LRUCache 最近最少使用算法

恩...安卓实训终于做完了 这边继续开更

很多简单的题目慢慢来更把,首先解决接受率比较低的

这次做的是LRUCache

原题如下

Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and set.

get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
set(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.

首先想到的是这样的思路

  • 使用单链表来存
  • 主类里存的是头结点 尾结点
  • 每次get遍历从head结点开始,直到找到或者到头为止
  • 每次put如果是已经有的key,修改其值,并放到链表尾
  • 如果是没有的值则新建一个结点放到尾巴上
  • 如果容量满了则去删改头结点

代码如下

package lru.cache;

public class LRUCache2 {

    private Item head,tail;
    private Integer capacity;
    private Integer count;
    
    public LRUCache2(int capacity) {
        this.capacity = capacity;
        count= 0;
        head = null;
        tail = null;
    }
    
    public int get(int key) {
        if(head == null)
            return -1;
        if(head.key == key)
            return head.value;
        if(tail.key == key)
            return tail.value;
        
        Item theValue = head.next;
        Item theValueBefore = head;
        while(theValue != null){
            if(theValue.key == key ){
                theValueBefore.next = theValue.next;
                tail.next = theValue;
                tail = theValue;
                theValue.next = null;
                return theValue.value;
            }
            theValueBefore = theValue;
            theValue = theValue.next;
        }
        return -1;

    }
    
    public void set(int key, int value) {
        if(head == null){
            head = new Item(value, key, null);
            tail = head;
        }
        Item temp = checkKeyPresent(key);
        if(temp != null){
            temp.value = value;
        }else{
            if(capacity.equals(count)){
                head = head.next;
                tail.next = new Item(value, key, null);
                tail = tail.next;
            }else{
                tail.next = new Item(value, key, null);
                tail = tail.next;
                count ++ ;              
            }
        }
    }
    
    public Item checkKeyPresent(int key){
        Item temp = head ;
        while(temp != null){
            if(temp.key == key )
                return temp;
            temp = temp.next;
        }
        return null;
    }
    class Item{
        public int value;
        public int key;
        public Item next;
        public Item(int value, int key, Item next) {
            super();
            this.value = value;
            this.key = key;
            this.next = next;
        }

    }
}

这样的做的结果是

这个方法在capacity=2048时 timeout

超时了啊...

好吧,从新审视一下

最耗时间的部分是set时需要
遍!历!已!经!有!的!全!部!结!点!
那么如果没有这个过程,或者这个过程消耗时间极短,效率应该会大幅上升再想KYY VALUE 好吧

hashMap就决定是你了!

而为了维护最近最少使用这一点, 还是维护链表最为方便,如果使用数组很难记录最近使用这个数值

对上述代码进行修改!

所以Key将作为索引,本质还是一个双向链表

talk is cheap,show you the code

更多的问题看注释就好

package lru.cache;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
/*
 * 之前用链表写的效率太差
 * 仔细检查代码
 * 发现最耗时间的部分是set时
 * 遍!历!已!经!有!的!全!部!结!点!
 * 那么如果没有这个过程,或者这个过程消耗时间极短
 * 就可以了...再想KYY VALUE 好吧 
 * hashMap就决定是你了!
 * 而为了维护最近最少使用这一点
 * 还是维护链表最为方便,如果使用数组很难记录最近使用这个数值
 * 所以对上述代码进行修改!
 * 所以Key将作为索引,本质还是一个链表
 */
public class LRUCache {

    private HashMap cache;
    private Item head, tail;
    private int capacity;
    private int count;
    
    public LRUCache(int capacity) {
        cache = new HashMap(capacity);
        this.capacity = capacity;
        count= 0;
        head = null;
        tail = null;
    }
    
    public int get(int key) {
        if(cache.isEmpty())
            return -1;
        
        if(!cache.keySet().contains(key))
            return -1;

        Item temp = cache.get(key);
        //分4种情况,分别为既是头结点又是尾结点、只是头结点、
        //只是尾结点和既不是头结点又不是尾结点
        if(temp.previous == null && temp.next ==null){
            return temp.value;
        }else if(temp.previous == null){
            head = temp.next;
            head.previous = null;
            tail.next = temp;
            temp.previous = tail;   
            tail = temp;
            temp.next = null;
            return temp.value;
        }else if(temp.next == null){
            return temp.value;
        }else{
            temp.previous.next = temp.next;
            temp.next.previous = temp.previous;
            temp.previous = tail;
            tail.next = temp;
            temp.next = null;
            tail = temp;
            return temp.value;
        }

    }
    
    public void set(int key, int value) {
        if(cache.isEmpty()){
            head = new Item(key,value);
            tail = head;
            cache.put(key, head);
            count ++;
            return;
        }
                
        Item temp = cache.get(key);
        if(temp != null){
            //如果存在,则修改该值,并且放到尾结点
            temp.value = value;
            
            if(head == tail){
                //如果是头结点又是尾结点
                //null
            }else if(temp.previous == null && temp.next != null){
                //如果只是头节点
                head = temp.next;
                head.previous = null;
                tail.next = temp;
                temp.previous = tail;
                tail = temp;
            }else if(temp.next == null && temp.previous != null){
                //如果只是尾结点
                //null
            }else {
                temp.next.previous = temp.previous;
                temp.previous.next = temp.next;
                tail.next = temp;
                temp.previous = tail;
                temp.next = null;
                tail = temp;
            }
        }else{
            //如果不存在
            if(capacity > count ){
                //不存在,且内容没满,则新建一个结点,放到尾部
                temp = new Item(key,value);
                tail.next = temp;
                temp.previous = tail;
                tail = temp;
                count ++ ; 
                cache.put(key, temp);
            }else{
                //不存在且内容已满,则修改头结点中内容,并放到尾巴上
                if(head == tail){
                    temp = head;
                    
                    cache.remove(temp.key);
                    temp.value = value;                 
                    temp.key = key;
                    
                    cache.put(key, head);
                }else{
                    temp = head;
                    cache.remove(temp.key);
                    temp.value = value; 
                    temp.key = key;
                    head = head.next;
                head.previous = null;
                temp.next = null;
                    tail.next = temp;
                    temp.previous = tail;
                    tail = temp;
                    cache.put(key, temp);
                }

            }
        }
    }
    
    class Item{
        public int value;
        public int key;
        public Item previous;
        public Item next;
        public Item(int key,int value) {
            super();
            this.value = value;
            this.key = key;
            this.next = null;
            this.previous = null;
        }

    }

}

你可能感兴趣的:(LeetCode之路2,LRUCache 最近最少使用算法)