LeetCode:链表

发布于:2025-04-17 ⋅ 阅读:(24) ⋅ 点赞:(0)

160. 相交链表

/**
 * 单链表的定义
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode l1 = headA;
        ListNode l2 = headB;

        while(l1 != l2){
            if(l1!=null){
                l1=l1.next; //指针移动到下一个节点
            }else{
                l1=headB;//指针移动到最后,换成另一个链表遍历
            }

            if(l2!=null){
                l2=l2.next;
            }else{
                l2=headA;
            }
        }
        return l2;

    }
}

206. 反转链表

讲解反转链表【基础算法精讲 06】_哔哩哔哩_bilibili

/**
 * 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 reverseList(ListNode head) {
        if(head==null || head.next==null)
            return head;

        //原地调整链表
        //利用cur、nxt、pre三个新指针
        ListNode cur = head;
        ListNode pre = null;

        while(cur!=null){
            //nxt指针为当前节点的下一个
            ListNode nxt = cur.next;
            cur.next = pre;
            pre = cur;
            cur = nxt;
        }
        return pre;
    }
}

21. 合并两个有序链表

【从零开始刷LeetCode】第四天:合并两个有序链表(动画演示、手写 Java 代码、详细注释、LeetCode 高频算法题)_哔哩哔哩_bilibili

/**
 * 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 mergeTwoLists(ListNode list1, ListNode list2) {
        if(list1==null) return list2;
        if(list2==null) return list1;

        //虚拟头节点
        ListNode dummy = new ListNode(-1);
        //虚拟前置指针
        ListNode pre = dummy;

        while(list1!=null && list2!=null){
            if(list1.val <= list2.val){
                pre.next = list1;
                list1=list1.next;
            }else{
                pre.next = list2;
                list2=list2.next;
            }
            pre = pre.next;
        }

        //以防一个链遍历完了,另一个没有遍历完
        if(list1==null && list2!=null)
            pre.next=list2;
        if(list1!=null && list2==null)
            pre.next=list1;
        
        return dummy.next;
    }
}

83. 删除排序链表中的重复元素

class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        ListNode cur = head;
        ListNode pre = new ListNode(-1);

        pre = head;

        while(cur!=null && cur.next!=null){
            if(cur.val==cur.next.val){
                pre=cur;
                cur.next=cur.next.next;
            }else{
                pre=cur;
                cur=cur.next;
            }
        }

        return head;
    }
}

19. 删除链表的倒数第 N 个结点

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {

        ListNode cur = head;
        ListNode dummy = head;
        int len=0;

        while(cur!=null){
            cur=cur.next;
            len++;
        }

        ListNode newCur = head;

        for(int i=0; i<len-n-1; i++){
            newCur=newCur.next;
        }

        newCur.next=newCur.next.next;

        return dummy;
        
    }
}
删除链表的倒数第N个节点这道题中,我写的newCur.next=newCur.next.next;
这一句为什么报错?

在您提供的代码中,报错的原因可能是因为当您试图删除倒数第N个节点时,
如果N等于链表的长度(即要删除的是头节点),
那么在执行 newCur.next = newCur.next.next; 这一行时,
newCur 实际上可能是 null,因为 len - n - 1 可能为 -1。

为了修复这个问题,您应该修改循环条件,并确保在删除节点之前 newCur 不是 null。
以下是修改后的代码:

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode cur = head;
        
        int len = 0;

        // 计算链表长度
        while (cur != null) {
            cur = cur.next;
            len++;
        }

        
        ListNode dummy = new ListNode(0); // 创建一个哑节点,指向头节点
        dummy.next = head;

//头节点可能会被删除,所有用一个dummy作为head的替身,最后返回的不是head,而是dummy.next
        ListNode newCur = dummy; // 从哑节点开始遍历

        // 找到要删除节点的前一个节点
        for (int i = 0; i < len - n; i++) {
            newCur = newCur.next;
        }

        // 删除节点
        newCur.next = newCur.next.next;

        return dummy.next; // 返回哑节点的下一个节点,即新的头节点
    }
}
创建了一个哑节点 dummy,它的 next 指向 head。这样即使删除的是头节点,我们也可以通过 dummy 正确地返回新的头节点。
循环条件从 len - n - 1 改为 len - n,因为我们要找到要删除节点的前一个节点。
返回值从 dummy 改为 dummy.next,这样即使头节点被删除,也能正确返回新的头节点。

24. 两两交换链表中的节点

class Solution {
    public ListNode swapPairs(ListNode head) {
        if(head==null || head.next==null) return head;

        ListNode dummy = new ListNode(-1);
        dummy.next=head;
        ListNode pre=dummy;

//pre的位置选取是待处理两个节点的前一个
//l1、l2都是在循环里设的
//熟悉过程
        while(pre.next!=null && pre.next.next!=null){
            ListNode l1 = pre.next;
            ListNode l2 = pre.next.next;
            ListNode nxt = l2.next;

            pre.next=l2;
            l2.next=l1;
            l1.next=nxt;
            pre=l1;

        }

        return dummy.next;
    }
}

234. 回文链表

class Solution {
    public boolean isPalindrome(ListNode head) {

        ListNode mid = findMiddle(head);
        ListNode list2 = reverseList(mid);


        while(list2!=null){
            if(head.val != list2.val){
                return false;
            }
            head=head.next;
            list2=list2.next;                
        }

        return true;

    }


    //快慢指针找中点
    public ListNode findMiddle(ListNode head){

        ListNode slow = head;
        ListNode fast = head;

        while(fast != null && fast.next != null){
            slow=slow.next;
            fast=fast.next.next;
        }

        return slow;
    }


    //还是反转链表
    public ListNode reverseList(ListNode head){

        if(head==null || head.next==null)
            return head;

        ListNode pre = null;
        ListNode cur = head;

        while(cur!=null){
            ListNode nxt = cur.next;
            cur.next = pre;
            pre = cur;
            cur = nxt;
        }
        return pre;
    }

}

141. 环形链表

public class Solution {
    public boolean hasCycle(ListNode head) {
        if(head==null || head.next==null)
            return false;

        ListNode slow = head;
        ListNode fast = head;

//存在fast.next.next这种越级调用时,需要确保fast.next不为空
        while(fast!=null && fast.next!=null){
            slow=slow.next;
            fast=fast.next.next;

            if(slow==fast)
                return true;                       
        }

        return false;
        
    }
}

142. 环形链表 II

public class Solution {
    public ListNode detectCycle(ListNode head) {

        ListNode slow = head;
        ListNode fast = head;

        while(true){

            if(fast==null || fast.next==null) return null;

            slow=slow.next;
            fast=fast.next.next;

            //定位到两针相遇位置,跳出,此时确定有环
            if(slow==fast)
                break;
        }
        
        //此时从head处走到环的开始处 与 从相遇处走到环的开始处 步数一样
        fast=head;

        while(fast!=slow){
            slow=slow.next;
            fast=fast.next;
        }
        return slow;
        
    }
}

725. 分隔链表

class Solution {
    public ListNode[] splitListToParts(ListNode head, int k) {

        ListNode[] ans = new ListNode[k];

        if(head==null) return ans;

        // 遍历链表
        int len = 0;
        ListNode cur = head;
        while (cur != null) {
            len++;
            cur = cur.next;
        }

        // 计算每组的长度 和 多余的长度
        int subLen = (len>k) ? (len/k):1;
        int rest = (len>k) ? (len%k):0;

        cur = head;
        int num = 0;
        while(cur!=null){
            //每组需要移动的长度
            int move = subLen + (((rest--)>0)?1:0);
            for(int i=0; i<move-1; i++){
                cur=cur.next;
            }

            ans[num]=head;
            head=cur.next;
            cur.next=null;
            cur=head;
            num++;
        }

        return ans;
    }
}

148. 排序链表

【力扣hot100】【LeetCode 148】排序链表|归并排序的应用_哔哩哔哩_bilibili

class Solution {
    public ListNode sortList(ListNode head) {
        if(head==null || head.next==null) return head;
        
        ListNode head2 = middleList(head);
        
        head = sortList(head);
        head2 = sortList(head2);

        return merge(head, head2);
    }


//找链表中点,并断链
    public ListNode middleList(ListNode head){
        ListNode dummy = new ListNode(-1);
        ListNode pre = dummy;

        ListNode slow = head;
        ListNode fast = head;

        while(fast!=null && fast.next!=null){
            //pre=pre.next 不行,有空指针
            pre=slow;
            slow=slow.next;
            fast=fast.next.next;
        }
        pre.next=null;

        return slow;
    }


//两个链表合成有序链表
    public ListNode merge(ListNode list1, ListNode list2){
        ListNode dummy = new ListNode(-1);
        ListNode cur = dummy;

        while(list1!=null && list2!=null){
            if(list1.val<list2.val){
                cur.next=list1;
                list1=list1.next;
            }else{
                cur.next=list2;
                list2=list2.next;
            }
            cur=cur.next;
        }

        //以防有链表没结束
        if(list1!=null && list2==null) cur.next=list1;
        if(list1==null && list2!=null) cur.next=list2;

        return dummy.next;

    }
}

138. 随机链表的复制

题解:leetcode上——> 两种实现+图解 138. 复制带随机指针的链

/*
// 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 head;

        Node pre = head;
        
//在每个节点后面设置新节点
        while(pre!=null){
            Node newNode = new Node(pre.val, pre.next, null);
            pre.next=newNode;
            pre=newNode.next;
        }

        pre=head;
//设置新节点的随机random指针
        while(pre!=null && pre.next!=null){
            if(pre.random!=null)
                pre.next.random=pre.random.next;

            pre=pre.next.next;
        }

        Node cur = head;

        Node dummy = new Node(-1);
        pre=dummy;

//设法将新旧两个链表分开
        while(cur!=null){
            pre.next=cur.next;
            pre=pre.next;

            cur.next=pre.next;
            cur=cur.next;           
        }

        return dummy.next;
    }
}

146. LRU 缓存

class LRUCache {

    private static class Node {
        Node pre, next;
        int key, value;

        // 构造器
        Node(int key, int value) {
            this.key = key;
            this.value = value;
        }
    }

    private final int capacity;
    private final Node dummy = new Node(0, 0);
    private final Map<Integer, Node> keyToNode = new HashMap<>();

    public LRUCache(int capacity) {
        this.capacity = capacity;
        dummy.next = dummy;
        dummy.pre = dummy;
    }

    public int get(int key) {
        Node node = getAndFront(key);
        if (node == null) {
            return -1;
        }
        return node.value;
    }

    //易错处
    public void put(int key, int value) {
        // 如果key的node存在
        Node node = keyToNode.get(key);
        if (node != null) {
            node.value = value;
            remove(node);
            addFront(node);
            return;
        }

        // 这个key不存在,新建node
        node = new Node(key, value);
        addFront(node);
        keyToNode.put(key, node);
        if (keyToNode.size() > capacity) {
            // 从表尾删除一个节点
            Node lastNode = dummy.pre;
            keyToNode.remove(lastNode.key);
            remove(lastNode);
        }

    }

    // 以上的put和get应基于以下几个基础操作
    // 删除节点
    public void remove(Node x) {
        x.pre.next = x.next;
        x.next.pre = x.pre;
    }

    // 从链表头插入
    public void addFront(Node x) {
        x.pre = dummy;
        dummy.next.pre = x;
        x.next = dummy.next;
        dummy.next = x;
    }

    // 用key get某个节点,并把节点移到链表头部
    public Node getAndFront(int key) {
        if (!keyToNode.containsKey(key))
            return null;

        Node node = keyToNode.get(key);
        remove(node);
        addFront(node);
        return node;
    }
}

2. 两数相加

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode dummy = new ListNode(0); // 辅助节点
        ListNode pre = dummy;
        
        //进位carry
        int carry=0;

        while(l1!=null || l2!=null){
            if(l1!=null){
                carry += l1.val;
                l1=l1.next;
            }
            if(l2!=null){
                carry += l2.val;
                l2=l2.next;
            }

            //新节点是carry的个位数
            pre.next = new ListNode(carry%10);
            pre = pre.next;
            
            //判断是否有进位
            carry = (carry>=10)?1:0;
        }

        //最后循环结束,如果有进位,还需要补上最后一个1(这个1是最高位的1)
        if(carry==1){
            pre.next = new ListNode(carry);
        }

        return dummy.next;
    }
}

25. K 个一组翻转链表(⭐)

【LeetCode 每日一题】25. K 个一组翻转链表 | 手写图解版思路 + 代码讲解_哔哩哔哩_bilibili

class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {

        ListNode dummy = new ListNode(-1, head);


        ListNode start_pre = dummy;
        ListNode end = dummy;

        while(true){
            //遍历end,至本组最后一个节点
            for(int i=0; i<k&&end!=null; i++)
                end=end.next;
            if(end==null) break;

            //start为本组第一个节点
            ListNode start = start_pre.next;

            //endNxt为下一组的最后一个节点
            ListNode endNxt = end.next;

            //翻转之前把链断掉
            end.next=null;

            //翻转本组节点
            start_pre.next = reverse(start);

            //翻转之后,本组的尾部去接下一组的头部
            start.next=endNxt;

            //调整各个指针位置
            end = start;
            start_pre = start;
        }

        return dummy.next;
    }

    public ListNode reverse(ListNode head){
        ListNode pre = null;
        ListNode cur = head;

        while(cur!=null){
            ListNode nxt = cur.next;
            cur.next=pre;
            pre=cur;
            cur=nxt;
        }

        return pre;
    }
}

23. 合并 K 个升序链表(hard)

迭代法
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        int n = lists.length;
        if (n == 0) return null;
        
        while(n>1){
            //index每次都初始化为0,因为要在lists的开头来存放合并出来的临时结果
            int index = 0;
            for(int i=0; i<n; i+=2){

                ListNode l1 = lists[i];
                ListNode l2 = null;
                if(i+1<n)
                    l2 = lists[i+1];

                lists[index++] = mergeTwoLists(l1, l2);
            }
            //index是lists数组新的长度
            n = index;
        }
        return lists[0];
    }
递归法
/**
 * 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.length == 0) return null;
        
        return merge(lists, 0, lists.length-1);
    }


    //递归法
    public ListNode merge(ListNode[] lists, int low, int high){
        if(low==high)
            return lists[low];

        int middle = low + (high-low)/2;
        ListNode l1 = merge(lists, low, middle);
        ListNode l2 = merge(lists, middle+1, high);

        return mergeTwoLists(l1, l2);
    }

    //合并两个有序链表
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        if (list1 == null && list2 == null)
            return null;
        if (list1 == null || list2 == null)
            return (list1 == null) ? list2 : list1;

        ListNode dummy = new ListNode(-1);
        ListNode pre = dummy;

        while (list1 != null && list2 != null) {
            if (list1.val < list2.val) {
                pre.next = list1;
                list1 = list1.next;
            } else {
                pre.next = list2;
                list2 = list2.next;
            }
            pre = pre.next;
        }

        if (list1 != null)
            pre.next = list1;
        if (list2 != null)
            pre.next = list2;

        return dummy.next;
    }
}

网站公告

今日签到

点亮在社区的每一天
去签到