删除排序链表中的重复元素(C语言)

文章目录

  • 初阶
  • 进阶

初阶

【题目描述】
给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回已排序的链表。

示例1:
输入:head = [1,1,2]
输出:[1,2]

示例2:
输入:head = [1,1,2,3,3]
输出:[1,2,3]

题目来源(力扣):删除排序链表中的重复元素

【基本思路】
做题时一定要结合题目描述以及示例去理解,以免出现理解上的偏差。
根据题目以及示例,意思是把本体留下,重复的干掉。
遍历一次链表即可,根据当前节点值与下一个节点值是否相等,可分为两种情况:
1)若相等,则删掉下一个节点。
2)若不等,则将下一个节点变为当前节点。
构成迭代。

【代码实现】

typedef struct ListNode ListNode;
struct ListNode* deleteDuplicates(struct ListNode* head){
    //空链表就直接返回空指针
    if(!head)  // 注:在条件判断中,head == NULL 和 !head 所起的作用是一样的。
        return NULL;

    ListNode* cur = head;
    while(cur->next && cur)  // 注意循环条件
    {
        ListNode* next = cur->next;
        //若相等,则删掉下一个节点
        if(cur->val == next->val)
        {
            cur->next = next->next;
            free(next);
        }
        //若不等,则将下一个节点变为当前节点
        else
            cur = cur->next;
    }

    return head;  
}

需要注意的是循环条件不能只有 cur 非空 这一个条件:若只有这一个循环条件,当 cur 的下一个节点是空时,会在 if 语句判断时导致程序崩溃(原因是对空指针进行解引用)。
因此,当 cur 的下一个节点是空时,为了终止循环,再加上 cur->next 不为空 就行。

进阶

【题目描述】
给定一个已排序的链表的头 head , 删除原始链表中所有重复数字的节点,只留下不同的数字 。返回已排序的链表 。

示例1:
输入:head = [1,2,3,3,4,4,5]
输出:[1,2,5]

示例2:
输入:head = [1,1,1,2,3]
输出:[2,3]

题目来源(力扣):删除排序链表中的重复元素 II

【基本思路】
根据题目以及示例的意思,与上面的题不同的是,这个是把相同值的节点都干掉。
遍历一次链表即可,根据是否有重复值的节点出现,可分为两种情况:
1)若出现,把整个重复值节点区间删掉。
2)若没有出现,则向后一步继续遍历。
构成迭代。

由于链表开头可能会出现连续几个相同值节点的删除,涉及第一个节点,因此设置哨兵位会更好,便于问题的解决。

【代码实现】

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;
}

链表的题一般有很多细节,做的时候需要多加注意,特别是有关指针的细节。

本专栏
有关链表的题目

其它专栏
有关数组的题目

你可能感兴趣的:(刷题,链表,c语言,数据结构)