简介:高效应对链表操作的 LeetCode 高频面试题
2023-12-11 17:12:27
删除链表中的元素:LeetCode 高频面试题剖析
一、简介
链表是一种广泛应用于各种编程场景的常见数据结构。在 LeetCode 面试中,针对链表的操作题目经常出现,掌握高效的链表操作技巧至关重要。本文将重点解析两道高频面试题,通过详细的步骤讲解和代码示例,帮助您全面理解链表删除操作。
二、题目 1:删除链表的倒数第 N 个结点
题目
给定一个链表,删除链表的倒数第 n 个结点,返回链表的头结点。
示例:
- 输入:head = [1,2,3,4,5], n = 2
- 输出:[1,2,3,5]
解决思路:
要删除链表的倒数第 n 个结点,我们可以使用双指针法。具体步骤如下:
- 创建两个指针 slow 和 fast,并将它们都指向链表头结点。
- 将 fast 指针向后移动 n 步。
- 当 fast 指针为 null 时,slow 指针指向的结点就是倒数第 n 个结点的前一个结点。
- 将 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;
}
四、常见问题解答
-
如何判断一个链表是否有环?
使用 Floyd 判圈算法。该算法使用两个指针,一个指针每次走一步,另一个指针每次走两步。如果链表中有环,这两个指针最终会相遇。
-
如何反转一个链表?
使用三个指针:prev、current 和 next。将 prev 指针指向 null,将 current 指针指向头结点,然后遍历链表,将 current 指针指向 next 指针,将 next 指针指向 prev 指针,将 prev 指针指向 current 指针。
-
如何判断两个链表是否相交?
使用哈希表。将一个链表的地址存储在哈希表中,然后遍历另一个链表,如果某个结点的地址已经在哈希表中,则说明两个链表相交。
-
如何合并两个有序链表?
使用一个哨兵结点。将哨兵结点的 next 指针指向头结点较小的链表。然后遍历两个链表,将较小的结点插入到哨兵结点之后。
-
如何删除链表中的所有奇数结点?
使用一个指针指向当前正在检查的结点,并在循环中判断当前结点的值是否是奇数。如果是,则将前一个结点的 next 指针指向当前结点的下一个结点。