一、题目
给你一个链表,删除链表的倒数第 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 <= 30
0 <= Node.val <= 100
1 <= n <= sz
通过次数355,363提交次数857,285
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
二、实现
参考了力扣的官方解题方法,本题主要有三种实现方法,1)找链表长度2)快慢指针3)栈
bug积累:
在调用对象的属性时,一定要防止空指针异常,在代码中while(curr.next != null)
,测试中出现了空指针异常,才发现忽略了一种非常特殊的情况,所以在调用之前一定要有清晰的逻辑判断,或者直接在前面加判断语句判断其是否是空指针。
removeNthFromEnd0中的while是可以被for()取代的,会比用while节省2行而且效果一样,所以在写了while和for后,要注意这时候是用while合适还是用for合适
package leetcode.question.bank;
import java.util.Stack;
public class Question19 {
// 必须申明为静态类,否则不能在静态方法中使用
private static class ListNode {
int val;
ListNode next;
ListNode(int val) {
this.val = val;
}
}
public static void main(String[] args) {
ListNode head = createList();
removeNthFromEnd0(head, 2);
showList(head);
System.out.println("");
ListNode head1 = new ListNode(1);
removeNthFromEnd1(head1, 2);
ListNode head2 = createList();
removeNthFromEnd2(head2, 2);
showList(head2);
}
private static ListNode removeNthFromEnd2(ListNode head, int n) {
// TODO Auto-generated method stub
ListNode first = new ListNode(0);
first.next = head;
Stack<ListNode> stack = new Stack<ListNode>();
ListNode curr = first;
while (curr != null) {
stack.push(curr);
curr = curr.next;
}
while (n-- >= 0) {
curr = stack.pop();
}
curr.next = curr.next.next;
return first.next;
}
// 利用快慢指针
private static ListNode removeNthFromEnd1(ListNode head, int n) {
// TODO Auto-generated method stub
// 在有效结点前添加一个空结点可以更容易进行下步操作
ListNode first = new ListNode(0);
first.next = head;
ListNode j = first;// 慢指针
int li = 0;
int lj = 0;
ListNode curr = first;// 快指针
while (li - lj != n) {
curr = curr.next;
li++;
}
// 一定要申明curr不是null,否则可能会出现空指针异常!
while (curr != null && curr.next != null) {
curr = curr.next;
j = j.next;
}
j.next = j.next.next;
// j.next和head是两个引用!
// return head;
return first.next;
}
private static void showList(ListNode head) {
// TODO Auto-generated method stub
ListNode curr = head;
while (curr != null) {
int val = curr.val;
System.out.print(val + " ");
curr = curr.next;
}
}
// 第一次遍历出长度,第二次移除相应位置
public static ListNode removeNthFromEnd0(ListNode head, int n) {
// 如果没有first结点,i指针不能直接处理删除第一个元素的情况
ListNode first = new ListNode(0);
first.next = head;
int length = getLength(head);
int i = 0;// 位置指针
ListNode curr = first;
while (i < length - n) {
curr = curr.next;
i++;
}
curr.next = curr.next.next;
return first.next;
}
private static int getLength(ListNode head) {
// TODO Auto-generated method stub
ListNode curr = head;
int length = 0;
while (curr != null) {
length++;
curr = curr.next;
}
return length;
}
public static ListNode createList() {
ListNode head = new ListNode(1);
head.next = new ListNode(2);
head.next.next = new ListNode(3);
head.next.next.next = new ListNode(4);
head.next.next.next.next = new ListNode(5);
return head;
}
}