代码随想录-链表2

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

力扣题目链接

基本思路

  1. 迭代,注意指针模拟操作,定义虚拟头节点用来指向链表
  2. 递归

迭代

class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode dummy = new ListNode(0, head); // 用哨兵节点简化代码逻辑
        ListNode node0 = dummy;
        ListNode node1 = head;
        while (node1 != null && node1.next != null) { // 至少有两个节点
            ListNode node2 = node1.next;
            ListNode node3 = node2.next;

            node0.next = node2; // 0 -> 2
            node2.next = node1; // 2 -> 1
            node1.next = node3; // 1 -> 3

            node0 = node1; // 下一轮交换,0 是 1
            node1 = node3; // 下一轮交换,1 是 3
        }
        return dummy.next; // 返回新链表的头节点
    }
}
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

递归

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

        ListNode node1 = head;
        ListNode node2 = head.next;
        ListNode node3 = node2.next;

        node1.next = swapPairs(node3); // 1 指向递归返回的链表头
        node2.next = node1; // 2 指向 1

        return node2; // 返回交换后的链表头节点
    }
}
  • 时间复杂度:O(n),其中 n 为链表长度。
  • 空间复杂度:O(n)。递归需要 O(n) 的栈空间。

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

力扣题目链接

基本思路

  1. 快慢指针,两个指针间隔n-1节点,当快指针到最后节点时,满指针刚好指向倒数第n个节点的前一个节点

方法代码

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy = new ListNode(0, head);
        ListNode fast = dummy;
        ListNode slow = dummy;
        while(n > 0){
            //这里快指针先移动n步,所以下面的判断是fast.next != null
            fast = fast.next;
            n--;
        }
        while(fast.next != null){
            fast = fast.next;
            slow = slow.next;
        }
        slow.next = slow.next.next;
        return dummy.next;
    }
}
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

面试题 02.07. 链表相交

力扣题目链接

基本思路

  1. 求出两个链表的长度,让两个指针指向短的链表长度的位置,之后同时遍历两个链表,若有指向相同的位置,则相交

方法代码

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        int lenA = 0;
        int lenB = 0;
        ListNode pA = headA;
        ListNode pB = headB;
        while(pA != null){
            lenA++;
            pA = pA.next;
        }
        while(pB != null){
            lenB++;
            pB = pB.next;
        }
        
        pA = headA;
        pB = headB;
        //让A为长的那个
        if(lenA < lenB){
            int temp = lenA;
            lenA = lenB;
            lenB = temp;

            ListNode tempNode = pA;
            pA = pB;
            pB = tempNode;
        }
        int d = lenA - lenB;
        while(d > 0){
            pA = pA.next;
            d--;
        }
        while(pA != null){
            if(pA == pB){
                return pA;
            }
            pA = pA.next;
            pB = pB.next;
        }
        return null;
    }
}
  • 时间复杂度:O(n+m)
  • 空间复杂度:O(1)

142. 环形链表 II

力扣题目链接

基本思路

  1. 代码随想录

方法代码

public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode fast = head;
        ListNode slow = head;
        ListNode meetNode;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            //先判断是否有环
            if (fast == slow) {
                //分别从相遇节点和头节点开始遍历
                meetNode = fast;
                ListNode p = head;
                while (p != meetNode) {
                    p = p.next;
                    meetNode = meetNode.next;
                }
                return p;
            }
        }
        return null;
    }
}
  • 时间复杂度:O(n),快慢指针相遇前,指针走的次数小于链表长度,快慢指针相遇后,两个index指针走的次数也小于链表长度,总体为走的次数小于 2n
  • 空间复杂度:O(1)
posted @ 2024-12-05 22:43  xloading  阅读(28)  评论(0)    收藏  举报