【力扣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 查找,依次将新节点的 nextrandom 指针指向正确的新节点,最终返回头节点。

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);
 */
相关推荐
ly76891 小时前
分布式一致性算法详解:从 2PC、3PC 到 Paxos、Raft、ZAB
分布式·算法
lv__pf1 小时前
Spring配置类解析 【TL spring 11】
java·前端·spring
zhougl9961 小时前
Java Spring Boot 爬虫技术全面介绍
java·spring boot·爬虫
阿维的博客日记1 小时前
保姆级教程-BBPE分词算法
算法·bbpe
奥莱维1 小时前
【无标题】
java·前端·javascript
不会就选b2 小时前
算法日常・每日刷题--<优先级队列>2
数据结构·算法
hanlin032 小时前
刷题笔记:力扣第189题-轮转数组
笔记·算法·leetcode
琥珀色糖2 小时前
leetcode hot100题(持续更新)移动零(双指针)
算法·leetcode·职场和发展·双指针·移动零
风流 少年2 小时前
Spring AI 2.0:Hello World
java·人工智能·spring