【链表】【中等】两数相加/倒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);
    }
}
相关推荐
CS创新实验室6 小时前
一棵树怎么做到“自平衡还不太费力“?——红黑树的旋转与染色
数据结构·算法·红黑树·408·计算机考研
Logic1016 小时前
C语言/数据结构位运算题解:异或XOR找出被挑选一次的果子编号——只出现一次的数字
c语言·数据结构·算法·数组·位运算·时间复杂度·空间复杂度
从小白到软工8 小时前
4-3 项目-学生成绩管理系统(上)
c语言·开发语言·数据结构·经验分享·ai编程
悠仁さん8 小时前
非类型模板参数的特化与偏特化
java·数据结构·算法
haluhalu.9 小时前
深入理解 AI Agent(1.2):Harness 工程——模型之外的竞争力
前端·数据结构·人工智能·python·langchain·个人开发
垆边人似月.9 小时前
幻兽防御战(贪心算法)
数据结构·算法
hflmwl810 小时前
RedisDesktopManager安装包中文版官方下载,redis可视化客户端工具下载
数据库·redis·缓存·可视化客户端工具
一枕槐安48710 小时前
大模型应用后端设计:上下文管理、缓存、降级策略的工程方案总结
java·spring·缓存
BeiGuTing_code10 小时前
C链表基础(二)有视频模拟!!!
c语言·链表·音视频
Cccp.12311 小时前
【leetcode】(十三)大数据处理
数据结构·算法·leetcode