返回

简介:高效应对链表操作的 LeetCode 高频面试题

前端

删除链表中的元素:LeetCode 高频面试题剖析

一、简介

链表是一种广泛应用于各种编程场景的常见数据结构。在 LeetCode 面试中,针对链表的操作题目经常出现,掌握高效的链表操作技巧至关重要。本文将重点解析两道高频面试题,通过详细的步骤讲解和代码示例,帮助您全面理解链表删除操作。

二、题目 1:删除链表的倒数第 N 个结点

题目

给定一个链表,删除链表的倒数第 n 个结点,返回链表的头结点。

示例:

  • 输入:head = [1,2,3,4,5], n = 2
  • 输出:[1,2,3,5]

解决思路:

要删除链表的倒数第 n 个结点,我们可以使用双指针法。具体步骤如下:

  1. 创建两个指针 slow 和 fast,并将它们都指向链表头结点。
  2. 将 fast 指针向后移动 n 步。
  3. 当 fast 指针为 null 时,slow 指针指向的结点就是倒数第 n 个结点的前一个结点。
  4. 将 slow 指针指向的结点的 next 指针指向倒数第 n 个结点的下一个结点。

代码实现:

public ListNode removeNthFromEnd(ListNode head, int n) {
    ListNode dummy = new ListNode(0);
    dummy.next = head;
    ListNode slow = dummy;
    ListNode fast = dummy;

    // 将 fast 指针向后移动 n 步
    for (int i = 0; i < n; i++) {
        fast = fast.next;
    }

    // 当 fast 指针为 null 时,slow 指针指向的结点就是倒数第 n 个结点的
    // 前一个结点
    while (fast != null) {
        slow = slow.next;
        fast = fast.next;
    }

    // 将 slow 指针指向的结点的 next 指针指向倒数第 n 个结点的下一个结点
    slow.next = slow.next.next;

    return dummy.next;
}

三、题目 2:删除排序链表中的重复元素

题目:

给定一个排序链表,删除所有重复的元素,留下只出现一次的元素。

示例:

  • 输入:head = [1,1,2,3,3]
  • 输出:[1,2,3]

解决思路:

我们可以使用一个指针指向当前正在检查的结点,并使用一个哑结点来存储结果。当遇到重复的元素时,我们只需跳过该元素即可。

代码实现:

public ListNode deleteDuplicates(ListNode head) {
    ListNode dummy = new ListNode(0);
    dummy.next = head;

    ListNode prev = dummy;
    ListNode current = head;

    while (current != null) {
        // 如果当前结点与前一个结点相同,则跳过该结点
        if (current.val == prev.val) {
            prev.next = current.next;
        } else {
            // 否则,将前一个结点的 next 指针指向当前结点
            prev = current;
        }

        // 移动 current 指针
        current = current.next;
    }

    return dummy.next;
}

四、常见问题解答

  1. 如何判断一个链表是否有环?

    使用 Floyd 判圈算法。该算法使用两个指针,一个指针每次走一步,另一个指针每次走两步。如果链表中有环,这两个指针最终会相遇。

  2. 如何反转一个链表?

    使用三个指针:prev、current 和 next。将 prev 指针指向 null,将 current 指针指向头结点,然后遍历链表,将 current 指针指向 next 指针,将 next 指针指向 prev 指针,将 prev 指针指向 current 指针。

  3. 如何判断两个链表是否相交?

    使用哈希表。将一个链表的地址存储在哈希表中,然后遍历另一个链表,如果某个结点的地址已经在哈希表中,则说明两个链表相交。

  4. 如何合并两个有序链表?

    使用一个哨兵结点。将哨兵结点的 next 指针指向头结点较小的链表。然后遍历两个链表,将较小的结点插入到哨兵结点之后。

  5. 如何删除链表中的所有奇数结点?

    使用一个指针指向当前正在检查的结点,并在循环中判断当前结点的值是否是奇数。如果是,则将前一个结点的 next 指针指向当前结点的下一个结点。