题目描述:
给定一个链表,删除链表的倒数第n个节点,并且返回链表的头节点。
题目解析:
显然,这个题目是考察链表的基本操作:包括链表的删除和连接,头节点等。
有一种明显的解题思路:
【1】采用两次循环遍历的方式:第一次遍历链表求出其长度L,第二次遍历链表找出需要删除节点的位置:(倒数第N个=顺数L-n+1)
具体代码如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution{
public:
ListNode* removeNthFromEnd(ListNode* head, int n){
//首先遍历获得L值
int len = 1; //用来保存链表长度
ListNode* tmp; //中间链表
for(tmp=head;tmp!=NULL;len++) //初始链表为tmp=head
tmp=tmp->next;
//第二次遍历进行删除操作
ListNode res(0); //初始化链表为一个元素(0),即哑节点
res.next=head; //哑巴节点的下一个节点是head
tmp = &res; //初始化返回值为res
for(int j=1;j<len-n;j++) //由于tmp会往后推移1个节点,因此只能是j<len-n,不能等于
{
tmp=tmp->next;
}
tmp->next=tmp->next->next; //直接跳过了倒数第n个节点
return res.next;
}
};
【2】除了采用两层的循环遍历之外,我们还可以采用双指针的单层遍历模式:(设置双指针p,q,间隔为n固定不变,当p指向null时,删除p的下一个节点)
具体的实现思路为:
(1)设置哑节点 dummyhead,使得指向head
(2)双指针初始化都指向虚拟节点(p=q=dummyhead)
(3)移动q使得p,q之间的元素间隔为n;
(4)然后固定n窗口,一起一定q,p. 直到q=null时,删除p指向的下一个节点。
具体实现如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution{
public:
ListNode* removeNthFromEnd(ListNode* head, int n){
ListNode* dummyhead= new ListNode(0); //开辟新节点,初始化为0
dummyhead->next = head;
ListNode* p=dummyhead;
ListNode* q=dummyhead;
for(int i=0;i<n+1;i++)
{
q=q->next;
} //保证p,q两个节点之间的距离为n
while(q) //当q为非空的时候,同时移动p,q
{
p=p->next;
q=q->next;
}
NodeList* delnode = p->next;
p->next = delnode->next;
delete delnode;//删除目标节点
ListNode* resultnode = dummyhead->next;
delete dummyhead; //删除哑节点
return resultnode;
}
};