代码随想录算法训练营day04| 24. 两两交换链表中的节点、19.删除链表的倒数第N个节点、面试题 02.07. 链表相交、142.环形链表II

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

题目链接
思路
代码随想录算法训练营day04| 24. 两两交换链表中的节点、19.删除链表的倒数第N个节点、面试题 02.07. 链表相交、142.环形链表II_第1张图片
代码随想录算法训练营day04| 24. 两两交换链表中的节点、19.删除链表的倒数第N个节点、面试题 02.07. 链表相交、142.环形链表II_第2张图片
代码

/**
 * 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 swapPairs(ListNode head) {
        // 设置一个虚拟头节点
        ListNode dummyHead = new ListNode(-1);
        dummyHead.next = head;
        // 定义一个指针令其指向虚拟头节点
        ListNode cur = dummyHead;
        // cur.next和cur.next.next就是要交换的节点,所以都不能为null
        while (cur.next != null && cur.next.next != null) {
            // 定义一个临时节点来存储第一个要交换的节点
            ListNode tmp = cur.next;
            // 定义一个临时节点来存储第二对要交换节点的第一个节点
            ListNode tmp1 = cur.next.next.next;
            // 步骤一
            cur.next = cur.next.next;
            // 步骤二
            cur.next.next = tmp;
            // 步骤三
            cur.next.next.next = tmp1;

            // 交换完成,cur向后移动两位,准备进行下一轮交换
            cur = cur.next.next;
        }
        // 交换完成返回头节点
        return dummyHead.next;
    }
}
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

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

题目链接
思路:双指针法,定义两个指针使其指向虚拟头节点,先让快指针移动n步,这里由于使用了虚拟头节点,所以移动n步所指向的位置为要删除节点的前一个节点,下面就是令快慢指针同时移动,直到快指针的下一个节点指向null,即快指针遍历完链表,然后删除目标节点。
代码

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        if (head == null || n <= 0) {
            return head;
        }
        // 定义一个虚拟头节点
        ListNode dummyHead = new ListNode(-1);
        dummyHead.next = head;
        ListNode slowIndex = dummyHead;
        ListNode fastIndex = dummyHead;
        // 这里fast指针先走n步,走到要删除节点的前一个节点,使快慢指针之间相差n
        for (int i = 0; i < n; i++) {
            fastIndex = fastIndex.next;
        }
        // 这时快慢指针同时移动
        while (fastIndex.next != null) {
            fastIndex = fastIndex.next;
            slowIndex = slowIndex.next;
        }
        // 删除目标节点
        slowIndex.next = slowIndex.next.next;
        return dummyHead.next;
    }
}

Leetcode 面试题 02.07. 链表相交

题目链接
思路
代码随想录算法训练营day04| 24. 两两交换链表中的节点、19.删除链表的倒数第N个节点、面试题 02.07. 链表相交、142.环形链表II_第3张图片
代码


public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode curA = headA;
        ListNode curB = headB;
        int lenA = 0;
        int lenB = 0;
        // 分别求出链表A和链表B的长度
        while (curA != null) {
            curA = curA.next;
            lenA++;
        }
        while (curB != null) {
            curB = curB.next;
            lenB++;
        }
        curA = headA;
        curB = headB;
        // 令curA为长链表的头,lenA为长链表的长度
        if (lenB > lenA) {
            ListNode tmpNode = curA;
            curA = curB;
            curB = tmpNode;
            int tmpLen = lenA;
            lenA = lenB;
            lenB = tmpLen;
        }
        // 求出链表的长度差
        int gap = lenA - lenB;
        // 移动curA使curA与curB在同一起点上(末尾位置堆起)
        while (gap-- > 0) {
            curA = curA.next;
        }
        // 遍历curA和curB,遇到相等则直接返回
        while (curA != null) {
            if (curA == curB) {
                return curA;
            }
            curA = curA.next;
            curB = curB.next;
        }
        return null;
    }
}
  • 时间复杂度:O(n + m)
  • 空间复杂度:O(1)

Leetcode 142.环形链表II

题目链接
思路:代码随想录
代码

public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode fastIndex = head;
        ListNode slowIndex = head;
        while (fastIndex != null && fastIndex.next != null) {
            slowIndex = slowIndex.next;
            fastIndex = fastIndex.next.next;
            // 相遇,说明有环
            if (slowIndex == fastIndex) {
                ListNode index1 = fastIndex;
                ListNode index2 = head;
                // 两个指针,从头结点和相遇结点,各走一步,直到相遇,相遇点即为环入口
                while (index1 != index2) {
                    index1 = index1.next;
                    index2 = index2.next;
                }
                return index1;
            }
        }
        return null;
    }
}

链表总结

  1. 虚拟头节点的使用,由于操作头节点和其他节点存在差异,所以使用虚拟头节点能够统一代码逻辑,这里需要注意的是使用了虚拟头节点,这个虚拟头节点就变成了链表的首位置,原本链表的index位置则变成了index+1的位置。
  2. 经典题目有
    • 链表的基本操作
    • 反转链表
    • 删除倒数第N个节点
    • 链表相交
    • 环形链表

你可能感兴趣的:(代码随想录算法训练营,链表,算法,数据结构,java,leetcode)