代码随想录-刷题第四天

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

题目链接:24. 两两交换链表中的节点

思路:直接用递归的方式来写,只要搞明白递归函数的定义,然后利用这个定义就可以完成这道题。

class Solution {
    // 定义:输入以 head 开头的单链表,将这个单链表中的每两个元素翻转,
    // 返回翻转后的链表头结点
    public ListNode swapPairs(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode first = head;
        ListNode second = head.next;
        ListNode others = head.next.next;
        // 先把前两个元素翻转
        second.next = first;
        // 利用递归定义,将剩下的链表节点两两翻转,接到后面
        first.next = swapPairs(others);
        // 现在整个链表都成功翻转了,返回新的头结点
        return second;
    }
}

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

题目链接:19. 删除链表的倒数第N个节点

思路:获取单链表的倒数第 k 个节点,就是想考察双指针技巧中快慢指针的运用,一般都会要求你只遍历一次链表,就算出倒数第 k 个节点。注意,有虚拟头结点操作更方便。

时间复杂度:O(n)

class Solution {
    // 主函数
    public ListNode removeNthFromEnd(ListNode head, int n) {
        // 虚拟头结点
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        // 删除倒数第 n 个,要先找倒数第 n + 1 个节点,传入参数为 dummy
        ListNode x = findFromEnd(dummy, n + 1);
        // 删掉倒数第 n 个节点
        x.next = x.next.next;
        return dummy.next;
    }

    // 返回链表的倒数第 k 个节点
    ListNode findFromEnd(ListNode head, int k) {
        ListNode p1 = head;
        // p1 先走 k 步
        for (int i = 0; i < k; i++) {
            p1 = p1.next;
        }
        ListNode p2 = head;
        // p1 和 p2 同时走 n - k 步
        while (p1 != null) {
            p2 = p2.next;
            p1 = p1.next;
        }
        // p2 现在指向第 n - k 个节点
        return p2;
    }
}

160. 链表相交

题目链接:160. 链表相交

思路:用两个指针 p1p2 分别在两条链表上前进,可以让 p1 遍历完链表 A 之后开始遍历链表 B,让 p2 遍历完链表 B 之后开始遍历链表 A,这样相当于「逻辑上」两条链表接在了一起。如果这样进行拼接,就可以让 p1p2 同时进入公共部分,也就是同时到达相交节点 c1

时间复杂度:O(n)

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        // p1 指向 A 链表头结点,p2 指向 B 链表头结点
        ListNode p1 = headA, p2 = headB;
        while (p1 != p2) {
            // p1 走一步,如果走到 A 链表末尾,转到 B 链表
            if (p1 == null) p1 = headB;
            else            p1 = p1.next;
            // p2 走一步,如果走到 B 链表末尾,转到 A 链表
            if (p2 == null) p2 = headA;
            else            p2 = p2.next;
        }
        return p1;
    }
}

142. 环形链表II

题目链接:142. 环形链表II

思路:基于 141. 环形链表 的解法,直观地来说就是当快慢指针相遇时,让其中任一个指针指向头节点,然后让它俩以相同速度前进,再次相遇时所在的节点位置就是环开始的位置。

时间复杂度:O(n)

public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode fast, slow;
        fast = slow = head;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow) break;
        }
        // 上面的代码类似 hasCycle 函数
        if (fast == null || fast.next == null) {
            // fast 遇到空指针说明没有环
            return null;
        }

        // 重新指向头结点
        slow = head;
        // 快慢指针同步前进,相交点就是环起点
        while (slow != fast) {
            fast = fast.next;
            slow = slow.next;
        }
        return slow;
    }
}

你可能感兴趣的:(数据结构,算法,链表,java)