题目:
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list
方法一
思路:
有点类似于移除元素。主要分为三种情况:
- 第一个节点
- 中间节点
- 最后一个节点
使用双指针法,pre指针先走 n 步,当pre走到链表末端时,post正好指向倒数第K个节点的前驱。
代码如下:
/**
* 删除链表的倒数第N个节点
* 第一个节点
* 中间节点
* 最后一个节点
* @param head
* @param n
* @return
*/
public ListNode removeNthFromEnd (ListNode head, int n) {
if (head == null) return head;
ListNode pre = head;;
ListNode post = head;
// pre 先走 n 步
for (int i = 1; i <= n; i++) {
if (pre != null) {
pre = pre.next;
}
}
if (pre != null) {
// 中间节点处理
// 当pre走到链表末端时,post正好指向倒数第K个节点的前驱
while (pre != null && pre.next != null) {
pre = pre.next;
post = post.next;
}
// 最后一个节点处理
if (post.next.next == null) {
post.next = null;
return head;
}
// 删除节点
post.next = post.next.next;
return head;
}
//第一个节点处理
head = head.next;
return head;
}
方法二
思路:
- 新建一个辅助头节点,这样子就可以统一处理了。我真的是太机智啦啊哈哈哈哈哈哈哈哈哈哈
- 让 pre 先走 n - 1 步。当 pre 指到最后一个节点,post 正好指向所要删除节点的前驱。
- 然后执行删除操作。
代码如下:
/**
* 找到倒数第n个节点
* 辅助头节点
* @param head
* @param n
* @return
*/
public ListNode deleteNthFromEnd3 (ListNode head, int n) {
ListNode dummyHead = new ListNode(-1);
dummyHead.next = head;
ListNode post = dummyHead;
ListNode pre = head;
// pre 先走 n - 1 步
for (int i = 1; i < n; i++) {
pre = pre.next;
}
// 判断条件到倒数第二个节点,然后执行完最后一次循环,pre正好指向最后一个节点
while (pre != null && pre.next != null) {
post = post.next;
pre = pre.next;
}
// 删除节点
post.next = post.next.next;
return dummyHead.next;
}
思路来自于----查找链表的倒数第N个节点
设置两个指针,pre先走 n - 1 步,当pre走到最后一个节点时,post正好指向倒数第 n 个节点。
代码如下:
/**
* 查找倒数第 n 个节点
* 双指针法
* @param head
* @param n
*/
public ListNode findNthFromEnd2 (ListNode head, int n) {
ListNode pre = head;
ListNode post = head;
// pre先走 n - 1 步
for (int i = 1; i < n; i++) {
pre = pre.next;
}
if (pre != null) {
// 当pre指向最后一个节点,post正好指向倒数第 n 个节点
while (pre != null && pre.next != null) {
pre = pre.next;
post = post.next;
}
return post;
}
// 输入[],0
return null;
}
如果在删除节点时,pre还是先走 n - 1 步,那么删除倒数第一个节点时就没办法处理。还要再设一个前驱。
错误代码如下:
/**
* 找到倒数第n个节点
* 双指针法
* @param head
* @param n
* @return
*/
public ListNode deleteNthFromEnd (ListNode head, int n) {
if (head == null) return head;
ListNode pre = head;
ListNode post = head;
// pre指针先走k - 1 步
for (int i = 1; i < n; i++ ) {
if (pre != null ) {
pre = pre.next;
}
}
// post指针正好指向倒数第n个节点
if (pre != null) {
// 中间元素
while (pre != null && pre.next != null) {
pre = pre.next;
post = post.next;
}
// 最后一个元素时
if (post.next == null) {
// 没法删最后一个节点
// 。。。
}
// 删除节点--交换删除
post.val = post.next.val;
post.next = post.next.next;
}
return head;
}