【链表】【中等】两数相加/倒N删除/两个交换/排序链表/LRU缓存

两数相加:逐位相加

原题链接

两个链表逐位走,当前位 % 10,进位 / 10,剩余 carry 标记进位

java 复制代码
public static ListNode addTwoNumbers(ListNode l1, ListNode l2) {
    ListNode res = new ListNode(0);
    ListNode cur = res;
    int carry = 0;//进位标识
    //l1和l2全为null时跳出循环
    while(l1 != null || l2 != null){
        int x =  (l1 != null) ? l1.val : 0;
        int y =  (l2 != null) ? l2.val : 0;

        int sum = x + y + carry;
        carry = sum / 10;
        int val = sum % 10;

        cur.next = new ListNode(val);
        cur = cur.next;
        if(l1 != null) l1 = l1.next;
        if(l2 != null) l2 = l2.next;
    }
    if(carry == 1){
        cur.next = new ListNode(1);
    }
    return res.next;
}

删除链表的倒数第N个节点:快慢指针 + 固定间距

原题链接

注意考虑删除节点为第一个节点的情况->虚拟头节点

java 复制代码
public ListNode removeNthFromEnd(ListNode head, int n) {
    ListNode dummy = new ListNode(-1);
    dummy.next = head;
    ListNode fast = dummy;
    ListNode slow = dummy;
    for (int i = 0; i <= n; i++) {
        fast = fast.next;
    }
    while (fast != null) {
        fast = fast.next;
        slow = slow.next;
    }
    slow.next = slow.next.next;
    return dummy.next;
}

两两交换链表中的节点:两两一组判别

原题链接

  • 注意先后顺序,right.next 的改变应该在 left = right.next 之前
java 复制代码
public static ListNode swapPairs(ListNode head) {
    ListNode dummy = new ListNode(0);
    dummy.next = head;
    ListNode prev = dummy;
    while (prev.next != null && prev.next.next != null) {
        ListNode left = prev.next;
        ListNode right = prev.next.next;
        prev.next = right;
        left.next = right.next;
        right.next = left;
        prev = left;
    }
    return dummy.next;
}

排序链表:归并排序

原题链接

使用插入排序,会进行两层循环,结果超时

① 找中点

② 切成两个链表

③ 左右分别递归排序

④ merge 两个有序链表

java 复制代码
public static ListNode sortList(ListNode head) {
    if(head == null || head.next == null){
        return head;
    }
    //先使用快慢指针将链表分为两半
    ListNode slow = head;
    ListNode fast = head;
    while(fast.next != null && fast.next.next != null){
        slow = slow.next;
        fast = fast.next.next;
    }
    ListNode p1 = head;
    ListNode p2 = slow.next;
    slow.next = null;
    p1 = sortList(p1);
    p2 = sortList(p2);
    //合并两个有序链表
    return mergeTwoLists(p1, p2);
}
//mergeTwoLists方法
public static ListNode mergeTwoLists(ListNode l1, ListNode l2) {
    ListNode dummy = new ListNode(0);
    ListNode head = dummy;
    while(l1 != null && l2 != null){
        if(l1.val < l2.val){
            head.next = l1;
            l1 = l1.next;
        }else{
            head.next = l2;
            l2 = l2.next;
        }
        head = head.next;
    }
    head.next = l1 != null ? l1 : l2;
    return dummy.next;
}

LRU缓存

原题链接

  • addToHead=这个节点现在不在链表里,把它插到头部

  • moveToHead=这个节点已经在链表里,先删掉,再重新插到头部

  • 注意进行区分,否则新节点会空指针异常

java 复制代码
public class LRUCache {
    private class DListNode{
        int key;
        int val;
        DListNode prev;
        DListNode next;
        public DListNode(int key, int val){
            this.key = key;
            this.val = val;
        }
    }
    int capacity;//缓存容量
    int size;//当前已经存在的节点数量
    Map<Integer, DListNode> map = new HashMap<>();
    DListNode dummy_head;
    DListNode dummy_tail;

    public LRUCache(int capacity) {
        this.capacity = capacity;
        size = 0;
        dummy_head = new DListNode(-1, -1);
        dummy_tail = new DListNode(-1, -1);
        dummy_head.next = dummy_tail;
        dummy_tail.prev = dummy_head;
    }

    public int get(int key) {
        if (!map.containsKey(key)) {
            return -1;
        }
        DListNode node = map.get(key);
        moveToHead(node);
        return node.val;
    }

    public void put(int key, int value) {
        //如果key存在,直接更新值
        if (map.containsKey(key)) {
            DListNode node = map.get(key);
            node.val = value;
            moveToHead(node);
            return;
        }
        if (size == capacity) {
            //如果缓存已满,删除尾部节点
            DListNode tail = dummy_tail.prev;
            map.remove(tail.key);
            removeNode(tail);
            size--;
        }
        //添加新节点到头部
        DListNode node = new DListNode(key, value);
        map.put(key, node);
        addToHead(node); 
        size++;
    }

    private void removeNode(DListNode node) {
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }
    //将节点添加到头部(节点原来不存在)
    private void addToHead(DListNode node) {
        node.prev = dummy_head;
        node.next = dummy_head.next;
        dummy_head.next.prev = node;
        dummy_head.next = node;
    }
    //将节点移动到头部(节点原来存在)
    private void moveToHead(DListNode node) {
        removeNode(node);
        addToHead(node);
    }
}
相关推荐
bro_Java6661 小时前
链表进阶:链表笔试真题
数据结构·链表
努力努力再努力wz1 小时前
【Redis入门系列】:从 RESP 协议到 redis-plus-plus:Redis 客户端编程与 C++ 接口设计
开发语言·数据库·c++·redis·分布式·缓存·架构
LB21122 小时前
力扣102 198 70 55
数据结构·算法·leetcode
刘天远2 小时前
企业 Agent 需求怎么写:数据结构、流程图与 Python 校验
数据结构·人工智能·python·流程图
明月_清风15 小时前
从二叉树到 B+ 树:一文搞懂工程中「树」的演化之道
数据结构·算法·go
渡我白衣15 小时前
并查集:基础认识与模拟实现
android·java·javascript·数据结构·c++·算法·并查集
血小板要健康16 小时前
链表 阶段算法总结
java·数据结构·笔记·算法·leetcode·链表
wuyk55520 小时前
107.FreeRTOS 链表深度解析:从原理到面试满分答案
c语言·开发语言·数据结构·stm32·单片机·链表·面试
-dzk-20 小时前
【链表】LC 138.随机链表的复制
数据结构·链表