Skip to content

链表


160. 相交链表

java
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode A = headA;
        ListNode B = headB;
        while (A != B) {
            A = A == null ? headB : A.next;
            B = B == null ? headA : B.next;
        }
        return A;
    }
}

206. 反转链表

java
// 使用虚拟头节点进行头插入,官解不需要头节点也可以
class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode dummy = new ListNode();

        ListNode cur = head, temp;
        while (cur != null) {
            temp = cur.next;
            cur.next = dummy.next;
            dummy.next = cur;
            cur = temp;
        }
        return dummy.next;
    }
}

234. 回文链表

java
class Solution {
    public boolean isPalindrome(ListNode head) {
        // 方法一:数组存储后判断
        // 方法二:快慢指针,慢指针走到中间一段并且翻转前半段链表
        // ----><----变为<----<----奇数需要处理slow,newhead和slow分别指向两段起点
        ListNode slow = head, fast = head, temp = null, newhead = null;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            temp = slow.next;
            slow.next = newhead;
            newhead = slow;
            slow = temp;
        }
        // 1 2 3 3 2 1 slow和fast刚好循环3次
        // 1 2 3 2 1 slow和fast循环2次
        if (fast != null) {
            slow = slow.next;
        }
        while (slow != null) {
            if (newhead.val != slow.val) {
                return false;
            }
            slow = slow.next;
            newhead = newhead.next;
        }
        return true;
    }
}

141. 环形链表

java
public class Solution {
    public boolean hasCycle(ListNode head) {
        ListNode slow = head, fast = head;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow) {
                return true;
            }
        }
        return false;
    }
}

142. 环形链表 II

java
public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode slow = head, fast = head;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            if (slow == fast) {
                slow = head;
                while (slow != fast) {
                    slow = slow.next;
                    fast = fast.next;
                }
                return slow;
            }
        }
        return null;
    }
}

21. 合并两个有序链表

java
class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        ListNode dummy = new ListNode();
        ListNode tail = dummy;
        while (list1 != null && list2 != null) {
            if (list1.val < list2.val) {
                tail.next = list1;
                list1 = list1.next;
            } else {
                tail.next = list2;
                list2 = list2.next;
            }
            tail = tail.next;
        }

        // 下面可以三目运算符
        if (list1 != null) {
            tail.next = list1;
        } else {
            tail.next = list2;
        }
        return dummy.next;
    }
}

2. 两数相加

java
// 进位carrybit,优先看灵神的吧
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        int carrybit = 0;
        ListNode dummy = new ListNode();
        ListNode tail = dummy;
        while (l1 != null && l2 != null) {
            int sum = l1.val + l2.val + carrybit;
            carrybit = sum / 10;
            tail.next = new ListNode(sum % 10);
            tail = tail.next;
            l1 = l1.next;
            l2 = l2.next;
        }
        tail.next = l1 != null ? l1 : l2;
        while (tail.next != null && carrybit != 0) {
            int sum = tail.next.val + carrybit;
            carrybit = sum / 10;
            tail.next.val = (sum % 10);
            tail = tail.next;
        }
        if (carrybit != 0) {
            tail.next = new ListNode(1);
        }

        return dummy.next;
    }
}


// 灵神代码更优雅
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode dummy = new ListNode(); // 哨兵节点
        ListNode cur = dummy;
        int carry = 0; // 进位
        while (l1 != null || l2 != null || carry != 0) { // 有一个不是空节点,或者还有进位,就继续迭代
            if (l1 != null) carry += l1.val; // 节点值和进位加在一起
            if (l2 != null) carry += l2.val; // 节点值和进位加在一起
            cur = cur.next = new ListNode(carry % 10); // 每个节点保存一个数位
            carry /= 10; // 新的进位
            if (l1 != null) l1 = l1.next; // 下一个节点
            if (l2 != null) l2 = l2.next; // 下一个节点
        }
        return dummy.next; // 哨兵节点的下一个节点就是头节点
    }
}

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

java
// 解法一:双指针,头节点,pre指向当前节点cur前一个,cur先走n步4,然后一起走
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy = new ListNode(0, head);
        ListNode pre = dummy, cur = head;
        while (n-- != 0) {
            cur = cur.next;
        }
        while (cur != null) {
            cur = cur.next;
            pre = pre.next;
        }
        pre.next = pre.next.next;
        return dummy.next;
    }
    
// 解法二:递归,需要返回值和一个共享的倒数idx记录
class Solution {
    private int idx; // 此处的idx需要在每层递归可见,不能--n

    public ListNode removeNthFromEnd(ListNode head, int n) {
        if (head == null) {
            return null;
        }
        head.next = removeNthFromEnd(head.next, n);
        if (++idx == n) {
            return head.next;
        }
        return head;
    }
}

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

java
// 哨兵节点,然后三个指针 pre node1 node2
class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode dummy = new ListNode(0, head);
        ListNode pre = dummy, node1, node2;

        while (pre.next != null && pre.next.next != null) {
            node1 = pre.next;
            node2 = node1.next;

            node1.next = node2.next;
            node2.next = node1;
            pre.next = node2;
            pre = pre.next.next;
        }
        return dummy.next;
    }
}

148. 排序链表

java
// 本题目细节:
// 1. 归并排序,单个节点以内无需排序直接返回
// 2. 多个节点,中间插入null拆分两段,注意fast预先走一步再进入循环(原因可以考虑2个节点情况)
// 3. 排序后的返回头需要再次利用,不能用前面的了
class Solution {
    public ListNode sortList(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode slow = head, fast = head.next; // fast先走一步方便利用slow断开原有链表,后面fast就没用了
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        ListNode temp = slow.next;
        slow.next = null;
        ListNode left = sortList(head);
        ListNode right = sortList(temp);
        // 上面已经拆分为两端并递归,开始合并,这里就是两个普通的链表进行合并操作,借助头节点
        ListNode dummy = new ListNode();
        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;
        }
        tail.next = left != null ? left : right;
        return dummy.next;
    }
}