持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第15天,点击查看活动详情
题目
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
示例 1:
输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]
示例 2:
输入:head = [1], n = 1
输出:[]
示例 3:
输入:head = [1,2], n = 1
输出:[1]
提示:
- 链表中结点的数目为
sz 1 <= sz <= 300 <= Node.val <= 1001 <= n <= sz
**进阶:**你能尝试使用一趟扫描实现吗?
解题
解题一:双指针
思路
使用快慢指针,确定链表的长度,从而确定倒数第 N 个数是在 链表的前半部分还是后半部分,然后进行删除操作
代码
/**
* 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 removeNthFromEnd(ListNode head, int n) {
ListNode slow = head;
ListNode fast = head;
int len = 1;
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
len += 2;
}
if (fast.next != null) {
len++;
}
if (n == len) {
// 删除头节点
return head.next;
}
// 在链表的后半段,或者在链表的前半段
slow = n > (len / 2) ? head : slow;
n = n > (len / 2) ? len - n -1: len / 2 - n;
for (int i = 0; i < n ; i++) {
slow = slow.next;
}
slow.next = slow.next.next;
return head;
}
}
总结
性能分析
- 执行耗时:0 ms,击败了 100.00% 的 Java 用户
- 内存消耗:39.4 MB,击败了 37.55% 的 Java 用户
解题二:栈
思路
- 遍历链表,将所有节点依次入栈
- 弹出栈第 N 个,就是要删除的节点的前一个节点
- 主要注意,可能会删除头节点,这时直接返回头节点的下一个节点即可
代码
import java.util.LinkedList;
/**
* 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 removeNthFromEnd(ListNode head, int n) {
if (head == null) {
return null;
}
Deque<ListNode> stack = new LinkedList<>();
ListNode temp = head;
while (temp != null) {
stack.push(temp);
temp = temp.next;
}
if (n >= stack.size()) {
// 删除头节点
return head.next;
}
for (int i = 0; i < n; i++) {
stack.pop();
}
ListNode prev = stack.pop();
prev.next = prev.next.next;
return head;
}
}
总结
性能分析
- 执行耗时:0 ms,击败了 100.00% 的 Java 用户
- 内存消耗:39.7 MB,击败了 36.14% 的 Java 用户