【力扣hot100】链表专题下|138、148、23、146

链表专题下

今天继续剩下的链表题

文章目录

  • 链表专题下
      • [138. 随机链表的复制](#138. 随机链表的复制)
      • [148. 排序链表](#148. 排序链表)
      • [23. 合并 K 个升序链表](#23. 合并 K 个升序链表)
      • 146.LRU缓存

138. 随机链表的复制

138. 随机链表的复制

遍历两遍链表,第一次建立新的节点,第二次建立节点之间的联系

java 复制代码
/*
// Definition for a Node.
class Node {
    int val;
    Node next;
    Node random;

    public Node(int val) {
        this.val = val;
        this.next = null;
        this.random = null;
    }
}
*/

class Solution {
    public Node copyRandomList(Node head) {
        if(head==null){
            return null;
        }
        Map<Node, Node> map = new HashMap<>();
        Node p = head;
        //创建新节点建立与原始节点的映射关系,map用于解决random节点的链接问题
        while (p != null) {
            map.put(p, new Node(p.val));
            p = p.next;
        }
        p = head;
        //将各个节点连接起来
        while (p != null) {
            Node newNode = map.get(p);
            newNode.next = map.get(p.next);
            newNode.random = map.get(p.random);
            p = p.next;
        }
        return map.get(head);//返回新的头节点
    }
}
  1. 第一次遍历(建映射) :遍历旧链表,为每个旧节点创建对应的新节点,并建立 Map<旧节点, 新节点> 的映射关系。
  2. 第二次遍历(连指针) :再次遍历旧链表,通过 Map 查找,依次将新节点的 next 和 random 指针指向正确的新节点,最终返回头节点。

148. 排序链表

148. 排序链表

归并排序

  1. 先用快慢指针找到每部分的中点
  2. 再根据升序合并起来
java 复制代码
/**
 * 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 sortList(ListNode head) {
        if(head == null||head.next == null){
            return head;
        }
        ListNode slow = head;
        ListNode fast = head.next;
        while(fast != null && fast.next != null){
            slow = slow.next;
            fast = fast.next.next;
        }
        ListNode second = slow.next;
        slow.next = null;
        ListNode first = head;
        first = sortList(first);
        second = sortList(second);
        return mergeList(first,second); 
    }

    public ListNode mergeList(ListNode left,ListNode right){
        ListNode dummy = new ListNode(0);
        ListNode tail = dummy;
        while(left != null && right != null){
            if(left.val < right.val){
                tail.next = left;
                left = left.next;
            }else{
                tail.next = right;
                right = right.next;
            }
            tail = tail.next;
        }
        if(left != null){
            tail.next = left;
        }else{
            tail.next = right;
        }
        return dummy.next;
    }
}

23. 合并 K 个升序链表

23. 合并 K 个升序链表

暴力

遍历数组,依次合并

java 复制代码
/**
 * 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 mergeKLists(ListNode[] lists) {
        if(lists == null || lists.length == 0){
            return null;
        }
        ListNode result = null;
        for(ListNode list:lists){
             result = mergeTwoLists(result, list);
        }

        return result;
    }

    public ListNode mergeTwoLists(ListNode left,ListNode right){
        ListNode dummy = new ListNode(0);
        ListNode tail = dummy;
        while(left != null && right != null){
            if(left.val < right.val){
                tail.next = left;
                left = left.next;
            }else{
                tail.next = right;
                right = right.next;
            }
            tail = tail.next;
        }
        if(left != null)tail.next = left;
        else tail.next = right;
        return dummy.next;
    }
}
优化

两两合并

对数组里的相邻两个链表两两合并,把合并后的结果存进新的数组,合并完一轮后得到一个新的数组,再次合并这个新的数组,最终得到一条链表

java 复制代码
/**
 * 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 mergeKLists(ListNode[] lists) {
        if(lists == null || lists.length == 0){
            return null;
        }
        while(lists.length > 1){
            List<ListNode> tempList = new ArrayList<>();
            for(int i = 0;i < lists.length;i += 2){
                ListNode l1 = lists[i];
                ListNode l2 = null;
                if(i + 1 < lists.length)l2 = lists[i + 1];
                tempList.add(mergeTwoLists(l1,l2));
            }
            lists = tempList.toArray(new ListNode[0]);
        }
        return lists[0];
    }

    public ListNode mergeTwoLists(ListNode left,ListNode right){
        ListNode dummy = new ListNode(0);
        ListNode tail = dummy;
        while(left != null && right != null){
            if(left.val < right.val){
                tail.next = left;
                left = left.next;
            }else{
                tail.next = right;
                right = right.next;
            }
            tail = tail.next;
        }
        if(left != null)tail.next = left;
        else tail.next = right;
        return dummy.next;
    }
}

146.LRU缓存

146. LRU 缓存

用哈希表和双向链表实现

  • 哈希表 负责 O(1) 的极速查找(通过 key 直接定位)。
  • 双向链表 负责 O(1) 的顺序维护(随时把节点拔出来插到队首,或者把队尾的节点删掉)
java 复制代码
class LRUCache {
    private int cap;// 容量
    private Node head,tail;
    private Map<Integer,Node> map;


    public LRUCache(int capacity) {
        cap = capacity;
        head = new Node(0,0);
        tail = new Node(0,0);
        head.next = tail;
        tail.pre = head;
        map = new HashMap<>();
    }
    
    public int get(int key) {
        if(map.containsKey(key)){
            Node tmp = map.get(key);
            remove(tmp);//删去双向链表里的该节点
            headinsert(tmp);//再把该节点插到头部
            return tmp.value;
        }
        return -1;
    }
    
    public void put(int key, int value) {
        if(map.containsKey(key)){
            remove(map.get(key));
            map.remove(key);
        }
        Node temp = new Node(key,value);
        headinsert(temp);
        map.put(key,temp);

        if(map.size()>cap){
            Node todel = tail.pre;
            remove(todel);
            map.remove(todel.key);
        }
    }

    //删除双向链表中指定节点
    private void remove(Node temp){
        Node tmp_pre = temp.pre;
        Node tmp_nxt = temp.next;
        tmp_pre.next = tmp_nxt;
        tmp_nxt.pre = tmp_pre;
    }

    //从双向链表头部插入节点
    private void headinsert(Node temp){
        Node nxt = head.next;
        head.next = temp;
        temp.next = nxt;
        temp.pre = head;
        nxt.pre = temp;

    }
}

class Node{
    int key;// 为了淘汰尾部节点时去哈希表里删除对应数据
    int value;
    Node pre;
    Node next;
    public Node(){}
    public Node(int key,int value){
        this.key = key;
        this.value = value;
    }
} 


/**
 * 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);
 */
相关推荐
强哥聊算力2 小时前
《算力江湖·英伟达传奇》第七集:ChatGPT出现前夜,英伟达发生了什么?
服务器·人工智能·算法·ai·chatgpt·gpu算力
哦虎!5 小时前
【JavaEE】网络初识
java
for_ever_love__5 小时前
MySQL ORDER BY 排序优化:从 Using filesort 到索引有序扫描(含双路 / 单路排序原理)
java·mysql·优化·存储·by·order·filesort
我是人✓6 小时前
Java文件上传三方式对比:从传统到SpringBoot
java·开发语言
欣栀♡6 小时前
JVM 频繁 Full GC 先看日志括号里的 cause,jstat 的 FGC 在 JDK 8 上会骗人
java·jvm
Navigator_Z6 小时前
LeetCode //C - 1289. Minimum Falling Path Sum II
c语言·算法·leetcode
CCblandy6 小时前
令牌桶在 0.9 倍负载超发 19%、固定窗口边界放行 20 个:四种限流算法同构实测
后端·python·算法·性能优化·架构
IT研究室6 小时前
最新计算机毕业设计选题推荐-基于spring boot的葡萄酒文化宣传网站-网站-文档指导-Java-springboot
java·spring boot·课程设计
慧都小项6 小时前
MyEclipse 中创建和测试 JAX-RS REST 接口:从项目配置到 REST Explorer
java·restful·myeclipse·jax-rs
Wang's Blog6 小时前
Java 项目实战: 交友项目 - 入门案例:编写 Dubbo 服务提供者
java·dubbo·交友