一学就会-----删除链表中的重复节点

题目描述

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。

图片示例:
在这里插入图片描述
在这里插入图片描述

思路一

解决该问题较简单,且在写代码时不易出错的做法如下:

遍历一遍链表,记录重复结点的结点值。
再遍历一遍链表,逐个删除重复结点。

在这里插入图片描述
在这里插入图片描述

注:该方法需要遍历两遍链表,且需要开辟额外的内存空间存储重复结点的结点值,所以一般不提倡。

代码示例

typedef struct ListNode ListNode;
struct ListNode* deleteDuplicates(struct ListNode* head){
    //空或只有一个节点
    if(!head || !(head->next))
        return head;
    //设置哨兵位
    ListNode* dummy = (ListNode*)malloc(sizeof(ListNode));
    dummy->next = head;
    ListNode* pre = dummy;  // 重复值节点区间的前驱节点
    ListNode* cur = pre->next;
    while(cur && cur->next)  // cur->next:当下面的if语句中next是空指针时,避免空指针的解引用
    {
        ListNode* next = cur->next;
        if(cur->val == next->val)
        {
            //跳过重复数字的节点,next是重复值节点区间的后一个节点
            while(next && cur->val == next->val)  // next:避免next最后是空指针,比如链表为[1,1]
                next = next->next;
            //连接
            pre->next = next;
            //删相同数字的节点
            while(cur != next)
            {
                ListNode* tmp = cur->next;
                free(cur);
                cur = tmp;
            }
        }
        else
        {
            pre = cur;
            cur = cur->next;
        }
    }
    
    head = dummy->next;
    free(dummy);
    dummy = NULL;
    return head;
}

思路二

我们当然应该尽可能在遍历一遍链表的情况下解决该问题,这时我们需要使用两个指针配合完成,该过程当中包含大量细节,大致步骤如下:

1.为了后续操作方便,先为该链表创建一个头结点。

在这里插入图片描述

2.使用指针prev和last遍历链表,初始时prev指向头结点,last指向头结点的下一个结点。

在这里插入图片描述

3.当last指向的结点值与其后一个结点的结点值相同时,last独自后移,直到last指向结点的结点值与其下一个结点的结点值不同为止,此时让prev指向的结点指向last的后一个结点,最后让last指向下一个结点(图中未后移)。

在这里插入图片描述

4.当last指向的结点值与其后一个结点的结点值不同时,prev和last一同向后移。

在这里插入图片描述

如此进行下去,直到last将链表遍历完,链表当中重复的结点也就全部被删除了,最后返回头结点指向的链表即可。

代码示例

    public ListNode deleteDuplicates(ListNode head) {
        if(head == null||head.next== null){
            return head;
        }
        ListNode dummyHead = new ListNode(-101);
        dummyHead.next = head;
        ListNode prev = dummyHead;
        ListNode cur = prev.next;
       while(cur!= null){
           ListNode sec = cur.next;
           if(sec == null){
               break;
           }
           if(cur.val!= sec.val){
               prev = prev.next;
           }else {
               while (sec!=null&&sec.val == cur.val){
                   sec = sec.next;
               }
               //到达此处有三种情况:
			//1、没有需要删除的重复结点,是因为last->next == nullptr到此
			//2、有需要删除的重复结点,是因为last->next == nullptr到此(链表后半段都需要删除)
			//3、有需要删除的重复结点,是因为last->val != last->next->val到此(链表中间某段需要删除)

               prev.next = sec;
           }
           cur = sec;
       }
        return dummyHead.next;
    }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值