写在前面
剑指offer:删除链表中重复的结点
题目要求
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
解法
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } }; */
class Solution {
public:
ListNode* deleteDuplication(ListNode* pHead)
{
if(!pHead||!pHead->next) return pHead;
ListNode* newHead = new ListNode(0), *cur = pHead;
newHead->next = pHead;
unordered_map<int,int> table;
while(cur) {
table[cur->val] += 1;
cur = cur->next;
}
cur = pHead;
ListNode* pre = newHead;
while(cur) {
if(table[cur->val]>1) {
ListNode* temp = cur->next;
pre->next = cur->next;
delete cur;
cur = temp;
}
else {
pre = cur;
cur = cur->next;
}
}
ListNode* res = newHead->next;
delete newHead;
return res;;
}
};
分析:
其实牛客网的题目的描述有点问题,重复的结点是指的就是给出的例子当中的连续出现的重复val的结点,还是说给出的例子只是某一种特例,重复就是指val相同的结点?
我一开始的写法就是当做删除所有重复val的结点。先遍历一遍链表,记录所有元素出现的次数,第二次遍历链表的同时,删除所有重复的结点。
注意的是,很可能原始的头结点会被删除,所以建立一个虚拟的新的头部节点解决这个问题。别忘记delete。
结果发现实际上就是第一种情况,重复val的结点只会连续出现,没必要考虑的这么麻烦。
删除操作只需要往后维护一个next如果和cur的值相等就一直往后走直到第一个和cur不同的结点然后执行删除操作。下面是牛客网的一个别人的答案,为什么要贴出来,因为这个人的删除就是简单的指针链接操作,如果原始的链表结点是new出来的他这个删除其实就是内存泄漏,同时他的新的头结点也没有释放。。。
class Solution {
public:
ListNode* deleteDuplication(ListNode* pHead)
{
if(pHead==NULL||pHead->next==NULL) return pHead;
else
{
//新建一个节点,防止头结点要被删除
ListNode* newHead=new ListNode(-1);
newHead->next=pHead;
ListNode* pre=newHead;
ListNode* p=pHead;
ListNode* next=NULL;
while(p!=NULL && p->next!=NULL)
{
next=p->next;
if(p->val==next->val)//如果当前节点的值和下一个节点的值相等
{
while(next!=NULL && next->val==p->val)//向后重复查找
next=next->next;
pre->next=next;//指针赋值,就相当于删除
p=next;
}
else//如果当前节点和下一个节点值不等,则向后移动一位
{
pre=p;
p=p->next;
}
}
return newHead->next;//返回头结点的下一个节点
}
}
};