题目描述:
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?
思想:
不需要提前进行一次遍历,得到链表的长度,只利用两个指针进行一次遍历。。例如链表为1,2,3,4,5,N=2,即删除倒数第二个。
- 初始两个指针pre和cur,指向第一个节点,即1,然后cur向前走n=2步,指向3,
- 然后pre和cur同时向后移动,直到cur指向最后一个节点5,此时cur.next=null
- 此时pre指向3,cur指向5,cur向后倒退n=2步就到了pre,所以此时pre的后一个节点pre.next就是要删除的节点
PS:链表中没有索引值,所以要巧妙的利用快慢指针
class ListNode{
int val;
ListNode next;
public ListNode(int x) {
val = x;
}
}
public class test1 {
public static ListNode removeNthFromEnd(ListNode head, int n) {
//如果只有一个结点,返回空,因为没法删除
if(head.next == null) return null;
//初始化快慢指针
ListNode pre = head, cur = head;
//先让cur走n步,此时cur指向第n+1个数
for(int i = 0; i < n; i++) cur = cur.next;
//如果cur==null,即说明链表长度为n,要删除的节点为头结点,左移返回head.next
if(cur == null) return head.next;
//pre和cur指针同时向后走,直到cur指向最后一个结点
while(cur.next != null) {
cur = cur.next;
pre = pre.next;
}
//此时cur指向最后一个数,pre与cur距离为n,所以pre为倒数第n+1个结点
//pre.next为倒数第n个结点,删除该结点即可
pre.next = pre.next.next;
return head;
}
//初始化链表
public static void add(ListNode node, int[] data) {
ListNode temp = node;
if(data.length == 0) return;
for(int i = 0; i < data.length; i++) {
temp.next = new ListNode(data[i]);
temp = temp.next;
}
}
//打印链表
public static void LinkedPrint(ListNode node) {
if(node == null) return;
while(node != null) {
System.out.println(node.val + " ");
node = node.next;
}
}
public static void main(String[] args) {
ListNode p = new ListNode(-1);
int[] nums = {1, 2, 3, 4, 5};
add(p, nums);
ListNode result = removeNthFromEnd(p.next, 2);
LinkedPrint(result);
}
}