描述
给出一个升序排序的链表,删除链表中的所有重复出现的元素,只保留原链表中只出现一次的元素。
例如:
给出的链表为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)