问题描述:
给定一个链表,删除链表的顺数及倒数第 n 个节点。
示例1:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了顺数第2个及倒数第2个节点后,链表变为 1->3->5.
示例2:
给定一个链表: 1->2->3->4->5, 和 n = 3.
当删除了顺数第3个及倒数第3个节点后,链表变为 1->2->4->5.
说明:
给定的 n 保证是有效的。
#include<iostream>
using namespace std;
struct ListNode
{
int val;
ListNode *next;
ListNode() : val(0), next(NULL) {}
ListNode(int x) : val(x), next(NULL) {}
ListNode(int x, ListNode *next) : val(x), next(next) {}
};
class Solution {
public:
ListNode* removeNth(ListNode* head, int n) {
//需要注意的是
//1、链表为空时,返回head;
//2、链表中只有一个结点时并且删除第一个结点,返回NULL
if(head==NULL) return head;
if(head->next==NULL&&n==1) return NULL;
//当删除第一个结点时,即n=1时,头结点可能会改变,所以声明一个newhead指针来指向该链表,链表完成操作后返回newhead->next即可
ListNode *newhead=new ListNode;
newhead->next=head;
ListNode *p=newhead,*q=newhead,*prep=newhead,*preq=newhead;
//先找到链表的顺数的第n个结点,由p指向链表的顺数的第n个结点,prep指向p的前一个结点
for(int i=0;i<n;i++){
prep=p;
p=p->next;
}
ListNode *p1=p;
//再找到链表的倒数的第n个结点,由q指向链表的顺数的第n个结点,preq指向p的前一个结点
//当p1指向空的时候,此时q指向链表的顺数的第n个结点
while(p1!=NULL){
preq=q;
q=q->next;
p1=p1->next;
}
/*分情况讨论:
1、当p和q指向同一个结点时,只需删除一个结点
2、当p和q指向不同结点并且两个结点不相邻,则删除p和q指向的两个结点
3、当p和q指向的结点相邻时,则一次性删除两个结点
p在q前,prep->next=q->next;
p在q后, preq->next=p->next;
完成操作后,返回newhead->next
*/
if(p==q){
prep->next=p->next;
}
else if(p!=q&&p->next!=q&&q->next!=p){
prep->next=p->next;
preq->next=q->next;
}
else if(p->next==q){
prep->next=q->next;
}
else if(q->next==p){
preq->next=p->next;
}
return newhead->next;
}
};
ListNode *createByTail()
{
ListNode *head;
ListNode *p1,*p2;
int n=0,num;
int len;
cin>>len;
head=NULL;
while(n<len && cin>>num)
{
p1=new ListNode(num);
n=n+1;
if(n==1)
head=p1;
else
p2->next=p1;
p2=p1;
}
return head;
}
void displayLink(ListNode *head)
{
ListNode *p;
p=head;
cout<<"head-->";
while(p!= NULL)
{
cout<<p->val<<"-->";
p=p->next;
}
cout<<"tail\n";
}
int main()
{
ListNode* head = createByTail();
int n;
cin>>n;
head=Solution().removeNth(head,n);
displayLink(head);
return 0;
}