牛客网剑指offer第56题——删除链表中重复的节点
题目:
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
思路:
讨论思路之前,先分析题目让我们做什么?删除重复节点,返回头节点。
对此,我将此问题描述成两步:
- 找到头节点
- 构成链表
1 /* 2 struct ListNode { 3 int val; 4 struct ListNode *next; 5 ListNode(int x) : 6 val(x), next(NULL) { 7 } 8 }; 9 */ 10 class Solution { 11 public: 12 ListNode* deleteDuplication(ListNode* pHead) 13 { 14 if(pHead == nullptr) 15 return nullptr; 16 if(pHead->next == nullptr) 17 return pHead; 18 //找到第一个head 19 ListNode*p1=pHead; 20 ListNode*p2=pHead; 21 while(p1 !=nullptr) 22 { 23 if((p1->val == p2->val))//当最坏的情况下,只有一个元素没有重复时,p1->next = null! 24 p1 = p1->next; 25 else 26 { 27 p2 = p1; 28 } 29 if(p2->next == nullptr || (p2->next !=nullptr && p2->val != p2->next->val)) 30 { 31 pHead = p2; 32 break; 33 } 34 35 } 36 37 if(p1 == nullptr)//说明所有元素都有重复! 38 { 39 pHead = nullptr; 40 return pHead; 41 } 42 ListNode*p3 = pHead; 43 p1 = p2->next;//考虑会不会越界 44 while(p1 != nullptr) 45 { 46 if(p1->next!=nullptr && p1->val == p1->next->val) 47 { 48 while(p1->next!=nullptr && p1->val == p1->next->val) 49 p1 = p1->next; 50 p2->next = p1->next; 51 p1 = p1->next; 52 } 53 else 54 { 55 p1 = p1->next; 56 p2=p2->next; 57 p3->next = p2; 58 } 59 p3 = p3->next; 60 } 61 return pHead; 62 } 63 };
21行-41行的代码,先帮助我们找到head节点在哪?因为比如链表结构如:1->1->1->2->3->3->4;显然此时head 指向2;而1->1->2;此时head指向2。而1->1->1,此时head指向null;
41行代码之前,完成了什么? 找到head节点,并让p2指向了head。下面就是正式寻找链表的过程。但我们应该注意:此时还需要第三个节点p3。p3的作用是引导构建新的不重复的链表;p1节点是当前访问的链表;p2节点为上一个不重复的节点。
我们先看48-51行代码干了什么?
比如head->2->3->3->3->4->4->5->6;即head指向2。此时p1指向1。显然执行完之后。p2->next指向了4。p1由原来的指向3变为指向4.也就是跳过了重复元素。下一次循环,对于4也是同样的处理。也就是执行完之后,p2-next指向了5,p1指向了5。所以48-51行代码的作用是帮助跳过重复元素。
再看55-57行
最开始p2 = head指向了2,然后呢p2->next指向了5.然后p2更新为p2->next,即p2指向了5。此时将p3->next赋值为p2,则完成了非重复元素的连接过程。然后p3 = p3->next。完成索引+1.
总之:这道题还是有些繁琐的,需要仔细思考细节!
stay foolish,stay hungry