8.剑指offer-删除链表中重复节点

1.题目

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。
​ 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5

链表结构

struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};

2.基本想法

就是删除重复的节点。没有什么trick。但是要注意的地方真不少。

设指针头节点为pHead1

易错点

  • 头节点是重复节点和链表中间的节点p是重复节点的处理方法不一样
    • 头节点的话,你可以直接删除;p是重复节点,你删除p和p的直接后驱节点,但是你还要保证p的前驱节点的next指针有指向。这就是他们不同的地方
  • 一对一对删除节点是错误的,因为一个重复节点里面存储的值可能重复了奇数次

验证实例

  • {1,1}
  • {1,1,1,2,2}
  • {1,2,2,2,3,3,4}
  • {1,2,2,2}

3.代码

  • 代码1

     ListNode* deleteDuplication(ListNode* pHead)
      {
         if(pHead==NULL || pHead->next==NULL){
             return pHead;
         }
         ListNode *p,*p1,*p2;
         while(pHead!=NULL && pHead->next!=NULL && pHead->val==pHead->next->val){
             p=pHead->next;
             while(p!=NULL && p->val==pHead->val){
                 p1=p->next;
                 pHead->next=p1;
                 delete p;
                 p=p1;
             }
             delete pHead; 
             pHead=p;
         }
    
         p=pHead;
         while(p!=NULL && p->next!=NULL){
             if(p->val!=p->next->val){
                 p=p->next;
             }else{
                 p1=p->next;
                 while(p1!=NULL && p1->val==p->val){
                     p2=p1->next;
                     p->next=p2;
                     delete p1;
                     p1=p2;
                 }
                 if(p1==NULL){
                     p2=pHead;
                     while(p2->next!=p)
                         p2=p2->next;
                     p2->next=NULL;
                     delete p;
                     break;
                 }else{
                     swap(p->val,p1->val);
                     p2=p1->next;
                     p->next=p2;
                     delete p1;
                 }
             }
    
         }     
         return pHead; 
      }
  • 代码2

      ListNode* deleteDuplication(ListNode* pHead)
      { // 如果重复的节点不止有两个呢?
          if(pHead==NULL)
              return NULL;
          ListNode *pLow,*pHigh,*pMiddle,*p;
          // 先选出头节点
          pLow=pHead;
          pHigh=pLow->next;
          while( pLow!=NULL && pHigh!=NULL && pLow->val==pHigh->val){
              while(pHigh!=NULL && pLow->val==pHigh->val ){
                  p=pLow;
                  pLow=pHigh;
                  pHigh=pHigh->next;
                  delete p;
              }
              pHead=pHigh;
              delete pLow;
              pLow=pHead;
              if(pLow!=NULL)
                  pHigh=pLow->next;
          }
          pMiddle=pHigh;
    
          if(pHigh!=NULL)
              pHigh=pHigh->next;
          while( pHigh!=NULL && pMiddle!=NULL ){
              if( pHigh->val==pMiddle->val  ){
                  while( pHigh!=NULL && pMiddle!=NULL && pMiddle->val==pHigh->val ){
                      pLow->next=pMiddle->next;
                      delete pMiddle;
                      pMiddle=pHigh;
                      pHigh=pHigh->next;
                  }
                  pLow->next=pMiddle->next;
                  delete pMiddle;
                  pMiddle=pHigh;
                  if(pHigh!=NULL)
                      pHigh=pHigh->next; 
              }else{
                  pLow=pMiddle;
                  pMiddle=pHigh;
                  pHigh=pHigh->next;
    
              }
    
          }
    
          return  pHead;
      }

    ps:代码2是我第一次遇见这道题时,提交的。有时我就在想,代码到底是越写越好,还是越写越差。经验即束缚,代码1中在删除节点的时候,我为什么不记录一下前一个节点是什么呢?大脑中还是保留着做过如何在 O(1) 时间内删除链表中的节点?这道题后,书本给我的答案或者经历给我的答案。

    写代码也时时刻刻能感觉到自己的局限。多么可怕的一件事情呀

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值