Leetcode19. 删除链表的倒数第 N 个结点

文章目录

    • 一、题目
    • 二、实现

一、题目

给你一个链表,删除链表的倒数第 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;
	}
}

你可能感兴趣的:(算法,Leetcode,快慢指针,栈,链表)