LeetCode Hot100 链表

LeetCode hot100 链表

24 两两交换链表中的节点

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode dummyHead = new ListNode(0);
        dummyHead.next = head;
        ListNode temp = dummyHead;
        while (temp.next != null && temp.next.next != null) {
            ListNode node1 = temp.next;
            ListNode node2 = temp.next.next;
            temp.next = node2;
            node1.next = node2.next;
            node2.next = node1;
            temp = node1;
        }
        return dummyHead.next;
    }
}

解法:

  • 递归调用

25 K个一组翻转链表

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        ListNode hair = new ListNode(0);
        hair.next = head;
        ListNode pre = hair;

        while (head != null) {
            ListNode tail = pre;
            // 查看剩余部分长度是否大于等于 k
            for (int i = 0; i < k; ++i) {
                tail = tail.next;
                if (tail == null) {
                    return hair.next;
                }
            }
            ListNode nex = tail.next;
            ListNode[] reverse = myReverse(head, tail);
            head = reverse[0];
            tail = reverse[1];
            // 把子链表重新接回原链表
            pre.next = head;
            tail.next = nex;
            pre = tail;
            head = tail.next;
        }

        return hair.next;
    }

    public ListNode[] myReverse(ListNode head, ListNode tail) {
        ListNode prev = tail.next;
        ListNode p = head;
        while (prev != tail) {
            ListNode nex = p.next;
            p.next = prev;
            prev = p;
            p = nex;
        }
        return new ListNode[]{tail, head};
    }
}

解法

  • 反转单个链表的方法:
  • 遍历链表,对每个节点保存后节点的值
  • 该节点的next指针指向前面的节点

146 LRU缓存

class LRUCache {

    class DList{
        int key;
        int val;
        DList pre;
        DList next;

        public DList(int k,int v,DList l1,DList l2){
            key = k;val = v; pre = l1; next = l2;
        }

        public DList(){}
//        public Dlist(int v){val = v;}

    }

    Map<Integer,DList> rec = new HashMap<>();
    DList head;
    DList tail;
    int size;
    int capacity;

    public LRUCache(int capacity) {
        this.size = 0;
        this.capacity = capacity;

        // 使用伪头部和伪结尾
        head = new DList();
        tail = new DList();
        head.next = tail;
        tail.pre = head;
    }

    public int get(int key) {
        DList node = rec.getOrDefault(key,null);
        if(node == null)
            return -1;

        // 把这个节点放到头节点,代表最先使用的
        moveToHead(node);
        return node.val;
    }

    public void put(int key, int value) {
        DList node = rec.getOrDefault(key,null);
        if(node != null){
            node.val = value;
            moveToHead(node);
            return;
        }else{
            if(size == capacity) {
                DList oldtail = removeTail();
                rec.remove(oldtail.key);
                size--;
            }

            DList tmp = new DList(key,value,null,null);


            // 直接插入头部
            tmp.next = head.next;
            tmp.pre = head;
            head.next = tmp;
            tmp.next.pre = tmp;

            rec.put(key,tmp);
            size++;

        }

    }

    private void moveToHead(DList node){
        DList nodepre = node.pre;
        DList nodenxt = node.next;
        nodepre.next = node.next;
        nodenxt.pre = node.pre;


        node.next = head.next;
        node.pre = head;
        head.next = node;
        node.next.pre = node;
    }

    /**
     * 返回删除的元素
     * @return
     */
    private DList removeTail(){
        DList tailpre = tail.pre;
        DList tailprepre = tailpre.pre;
        tailprepre.next = tail;
        tail.pre = tailprepre;
        return tailpre;
    }
}

解法

  • map + LinkedList
  • 用双向链表,在容量满时能快速移除最后一个有效元素
  • 对头、对尾双指针
  • 在put或get时,将该节点放到链表队头,代表最先使用

关于 LinkedHashMap

底层实现: HashMap + 双向链表
在这里插入图片描述

  • 插入顺序为 key1 , key2 ,key3 ,key4
  • 即可获得上方图示的结果

注意:
新插入的节点会放到最后
head指向的节点为第一个放入的节点

LRU的应用

class LRUCache extends LinkedHashMap {

    private int capacity;

    public LRUCache(int capacity) {
        //accessOrder为true
        super(capacity, 0.75F, true);
        this.capacity = capacity;
    }

    public int get(int key) {
        return (int)super.getOrDefault(key, -1);
    }

    public void put(int key, int value) {
        super.put(key, value);
    }

    protected boolean removeEldestEntry(Map.Entry eldest) {
        return size() > capacity;
    }
}

这里重写了removeEldestEntry方法,然后removeEldestEntry方法在afterNodeInsertion中被调用,如果这个方法返回真,那么就会删除head指向的节点。根据每次get的节点都会放到尾部的特性,所以head指向的节点就是最久没有使用到的节点,所以可以删除。由于我们每次put完(HashMap#putVal())都会调用这个afterNodeInsertion方法,所以可以上面的设计可以使put过后如果size超了,将删除最久没有使用的一个节点,从而腾出空间给新的节点。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值