描述
        给出一个升序排序的链表,删除链表中的所有重复出现的元素,只保留原链表中只出现一次的元素。
例如:
给出的链表为1→2→3→3→4→4→5, 返回1→2→5.
给出的链表为1→1→1→2→3, 返回2→3.
示例1
输入:{1,2,2}
返回值:{1}

方法一:递归求解
核心思想:
        采用递归的思想求解。每次递归则需要比较并删除重复的元素。本次的思想跟递归逆置链表很像,唯一的不同就是处理逻辑不同。删除重复链表的处理逻辑是每次都要判断是否有重复项,有重复项需要直接删除,同时连同当前节点也要删除。

核心代码:

ListNode* deleteDuplicates(ListNode* head) {
    if(head == nullptr || head->next == nullptr)       //节点不存在或者只有一个节点时,递归结束
        return head;

    ListNode* cur = head->next;
    if(head->val == cur->val) {    //head与cur值相等,则改变head的位置
        while(cur != nullptr && head->val == cur->val)   //循环遍历删除所有除head所指节点之外的其他重复节点
            cur = cur -> next;
        head = deleteDuplicates(cur);    //head指针直接指向返回的结果,跳过之前重复的节点(即重复节点的第一个节点断链)
    } 
    else                       //head与cur值不相等,则head不变
        head->next = deleteDuplicates(cur);
    return head;     
}

复杂度分析:
        递归n次,因此时间复杂度为O(N)。而每次递归都需要一个额外的变量保存,因此空间复杂度为O(N)
时间复杂度O(N)
空间复杂度O(N)

方法二:引入空节点遍历遍历
核心思想:
        引入一个新的空节点,作为链表的头结点。逐个遍历链表节点,由于需要删除所有的重复节点(包括重复节点中第一个出现的节点),因此这里还需要引入一个变量记录重复节点中第一个节点的值,并逐个与后续的节点值相比较,然后逐个删除。

图解:
图片说明

核心代码:

ListNode* deleteDuplicates(ListNode* head) {
    ListNode* dummp = new ListNode(-1);
    dummp->next = head;     //空节点插入链表头部
    ListNode* p = dummp;

    while(p->next && p->next->next){      //每次都是2个节点判断
        if(p->next->val == p->next->next->val){      //存在重复节点
            int num_flag = p->next->val;          //记录第一个重复节点的值
            while(p->next && p->next->val == num_flag)    //循环遍历后续节点的值,并与记录的节点值比较,相同则逐个删除
                p->next = p->next->next;
        }else     //本轮不存在重复节点,值链表指针后移
            p = p->next;
    }
    return dummp->next;    //返回结果
}

复杂度分析:
        代码循环遍历链表,循环次数为链表的长度,因此该方法的时间复杂度为O(N)。由于没有采用额外的空间,因此空间复杂度为O(1)
时间复杂度O(N)
空间复杂度O(1)