题目描述:
Given a linked list, remove the nth node from the end of list and return its head.
For example,
Given linked list: 1->2->3->4->5, and n = 2.
After removing the second node from the end, the linked list becomes 1->2->3->5.
Note:
Given n will always be valid.
Try to do this in one pass.
题目大意是:删除单链表的倒数第n个节点,返回头节点。
这道题思路很简单,就是设置两个指针,一个指针先向前走n-1步,然后和另一个一起向前走,当第一个指针到达链表末尾时,第二个指针的位置就是倒数第n个节点,要注意几个边界条件:
1、如果n等于链表节点个数,即要删除的节点是头节点
2、所给的n大于链表的节点个数或者n不合法(如小于或等于0,即使题目说明这种情况可以忽略,我们也应该考虑到)
此外,因为链表为单链表,无法直接获得某节点的直接前驱,因此我们需要再增加一个指针来记录倒数第n个节点的前驱,以便删除节点。
代码如下:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
public class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
if(head == null || n <= 0)
return null;
ListNode p1 = head;//先走n-1步
ListNode p2 = head;//记录要删除节点
ListNode p3 = head;//记录要删除节点的前驱
int i;
for(i = 0;i < n-1;++i) {
if(p1.next != null)//防止出现n大于链表长度的情况
p1 = p1.next;
else
return null;
}
if(p1.next == null) {//要删除的是头节点
head = head.next;
return head;
}
int count = 0;
while(p1.next != null && p2.next != null) {
p1 = p1.next;
p2 = p2.next;
//比要删除的节点慢一步
if(count > 0)
p3 = p3.next;
count++;
}
//删除节点
p3.next = p2.next;
return head;
}
}
总结:这类关于链表的题目有一些相似性,例如求链表的中间节点,如果是奇数个节点,返回中间的,如果是偶数个节点,返回中间两个中的任何一个。也可以设置两个指针,它们开始都指向头节点,然后一个指针每次走一步,另一个每次走两步,当走的快的节点到达尾部时,走的慢的节点正好在链表中间位置。
再例如判断单链表是否为环形结构,指针设置方式跟上面相同,判断条件是走的快的指针如果能够追上走的慢的指针说明有环。