Remove Nth Node From End of List
Total Accepted: 74559 Total Submissions: 274808 Difficulty: EasyGiven 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个位置跟着它走,当第一个指针到达最后一个节点时,第二个指针正好在倒数第n+1个节点,这个时候正好进行删除操作,值得注意的是如果第二个指针正好在倒数第n个节点,那么没法进行删除操作。
另外,如果要删除的是第一个节点,那么需要特殊的处理,即直接更新head指针到head->next,即让它指向第二个节点即可。
下面是完整代码
#include <iostream>
using namespace std;
struct ListNode
{
int val;
struct ListNode *next;
};
struct ListNode* removeNthFromEnd(struct ListNode* head, int n)
{
struct ListNode *f, *s;
f = head;
s = head;
while(n > 0)
{
f = f->next;
n--;
}
if(f == NULL)
{
return head->next;
}
while(f->next != NULL)
{
f = f->next;
s = s->next;
}
s->next = s->next->next;
return head;
}
int main()
{
int inputSize;
cout<<"Input the size of input:\n";
cin>>inputSize;
ListNode* head = NULL;
ListNode** p;
p = &head;
for(int i = 0; i < inputSize; i++)
{
if((*p) != NULL)
{
(*p)->next = (ListNode*)malloc(sizeof(ListNode));
cin>>(*p)->next->val;
(*p)->next->next = NULL;
}
else
{
(*p) = (ListNode*)malloc(sizeof(ListNode));
cin>>(*p)->val;
(*p)->next = NULL;
}
p = &((*p)->next);
}
cout<<"\nInput which index to delete\n";
int n;
cin>>n;
ListNode* nhead = removeNthFromEnd(head, n);
for(int i = 0; i < inputSize - 1; i++)
{
cout<<nhead->val<<" ";
nhead = nhead->next;
}
return 0;
}