NC24 删除有序链表中重复的元素-II
题意分析:
给一个有序的链表,删除其中出现的重复元素
示例:链表1→2→3→3→4→4→5, 删除重复元素后,变为1→2→5。
解释:在原有链表中,3和4出现了多次,因此把所有的3,4都删除,最后返回了1→2→5。
题解一(遍历):
在NC25中,我们删除了重复的元素,并且保留了一个,在这一题中,我们需要将所有出现的重复元素删除,我们可以在NC25上更进一步,在最后把重复元素删掉之后,再删掉保留的重复元素。
在中间一幅图删掉1后,变成第三张图。这是我们发现指针flag与p不相同且值不同,这时就要删除掉flag指向的元素。但flag是链表头元素,删掉就没法访问链表了。
这里我们设置一个伪链表头,指针dummy,指向head。
按照之前删除重复元素删除flag指向的元素。
我们初始化四个个指针:指针dummy指向head,用作伪头,最后用于返回结果。指针q指向flag前一个元素。指针flag指向重复的元素,指针p用于遍历链表。整体步骤如下:
- 删除重复元素(NC25)
- 删除保留的重复过的元素,我们使用一个bool变量t表示flag指针值是否被重复过了。为真,删除指针flag,为假则pass。
代码实现如下:
ListNode* deleteDuplicates(ListNode* head) { ListNode *flag = head; ListNode *p = head; ListNode *dummy = new ListNode(INT_MIN); dummy->next = head; ListNode *q = dummy; bool t = false; while(p){ if(flag==p){ p = p->next; } else if(flag!=p&&flag->val!=p->val&&!t){ q = flag; flag = p; } else if(flag!=p&&flag->val!=p->val&&t){ q->next = flag->next; free(flag); flag = q->next; t = false; } else if(flag!=p&&flag->val==p->val){ t = true; flag->next = p->next; free(p); p = flag->next; } } if(t){ q->next = flag->next; free(flag); flag = q->next; } return dummy->next; }
时间复杂度:。我们只遍历了一遍链表
空间复杂度:。我们额外申请了4个指针。常量空间。
题解二(使用set)
我们先遍历一遍链表,找出重复过的元素,存入到set中,之后再遍历一遍链表,如果该元素出现在set中,我们就不保留该结点,如果没有,我们就保留。
ListNode* deleteDuplicates(ListNode* head) { // write code here ListNode* dummy = new ListNode(-100); dummy->next = head; ListNode* p = dummy,*q=head; set<int>v; while(p&&q){ if(p->val==q->val){ v.insert(p->val); q = q->next; } else{ p = q; q = q->next; } } p = dummy,q=head; while(p&&q){ if(v.find(q->val)!=v.end()){ p->next= q->next; free(q); q = p->next; } else{ p = q; q = q->next; } } return dummy->next; }
时间复杂度。set的查询复杂度为我们在遍历链表时候,每一次都对set发起了一次查询。所有总的时间复杂度为。
空间复杂度:与重复过的元素有关。