剑指OFFER题47------按牛客网热度排序
时间:2019.1.16.1946
作者:Waitt
题目
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
时间限制:1秒 空间限制:32768K 热度指数:234318
解答
思路1
用一个栈q 依次存储结点地址,t指向当前栈顶结点在链表中的下一结点。
当发现t结点与栈顶结点相同时,将值赋给变量sh。
每次都判断栈顶是否与变量sh相同,若相同,则删除该结点并弹出栈顶,且让新的栈顶的next为t结点。
当栈为空或栈顶结点与t不相同时,则将t结点入栈,将t指向它的下一结点。重复循环直至尾节点。
若尾节点也为重复结点,则应将新的尾节点的next指针指向NULL。
栈底则为新链表的头节点。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* deleteDuplication(ListNode* pHead)
{
if(!pHead)
return pHead;
stack<ListNode*> q;//存储结点指针的栈
ListNode *hh;//指向删除完后链表的头节点
ListNode *t;//指向栈q顶结点的链表中的下一个结点
ListNode *s;//指向t的下一个结点
int sh;//记录相同结点的值的变量
t=s=pHead;
q.push(t);//先存入第一个结点
s=t->next;
while(s)//每次循环仅删除一个结点
{
t=s;
s=s->next;
if(q.size()&&(q.top()->val)==(t->val))
//确保可以访问q.top(),当当前栈顶的值与下一结点的值相等时
{
sh=(q.top()->val);//给sh赋值
}
if(q.size()&&(q.top()->val)==sh)
//确保可以访问q.top(),当当前栈顶的值与sh值相等时,应该弹出删除该结点,并弹出栈顶
{
delete q.top();
q.pop();
if(q.size())
q.top()->next=t;
}
if(q.empty()||(q.top()->val)!=(t->val))
//当栈为空或者栈顶结点值不等于下一结点值时,下一结点可入栈
{
q.push(t);
}
}
if(q.size()&&(q.top()->val)==sh)
//进行最后一个结点判断,当最后一个结点也为重复节点时,也应该删除该结点
{
delete q.top();
q.pop();
if(q.size())
q.top()->next=NULL;//此处变为栈顶结点变为新链表的尾节点,所以应该指向NULL
}
while(q.size())//寻找新链表的头节点
{
hh=q.top();
q.pop();
}
return hh;
}
};
每次对q.top()进行访问时,应该和q.size()与运算,确保可以访问到q.top()。
例如:if(q.size()&&(q.top()->val)==(t->val))
思路2
四指针法,仅通过指针操作进行删除
每次大循环均需删除所有值相同的结点
分三种情况:
情况1:头结点在一直变化
情况2:头结点变化完毕,后续遍历发现重复结点
情况3:头结点变化完毕,后续遍历暂未发现重复结点
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* deleteDuplication(ListNode* pHead)
{
if(!pHead)
return pHead;
ListNode* a;//当前结点
ListNode* b;//当前结点的下一结点
ListNode* c=NULL;//新链表的头节点
ListNode* d=NULL;//当前结点的上一结点
c=a=b=pHead;
b=a->next;
while(b)//每次循环可以删除所有值相同的结点
{
bool i=0;//标志位,判断是否有重复出现
while(b&&(a->val)==(b->val))//当出现重复时
{
i=1;//标志位置1
delete a;
a=b;
b=a->next;
}
if(i==1)//说明有重复情况
{
i=0;//重置标志位
if(d==NULL)//说明之前头结点一直在变动
{
delete a;
a=b;
c=a;//赋值新的头结点
if(a)//当当前结点不为NULL时,才会有下一结点
b=a->next;
}
else//说明此时修改的不是头结点
{
delete a;//删除当前结点
a=b;
d->next=a;//将上一结点的指针指向删除后的当前结点
if(a)//当当前结点不为NULL时,才会有下一结点
b=a->next;
}
}
else//说明并无重复,d后移一位,a后移一位
{
d=a;
a=b;
if(a)
b=a->next;
}
}
return c;
}
};