声明哑结点,便于操作头结点。声明左指针 p p p , p p p 指向可能删除结点的前一个位置。 声明右指针 q q q , q = p − > n e x t − > n e x t q=p->next->next q=p−>next−>next , p / q p/q p/q 之间隔着一个结点,便于删除操作。当 q q q 非空,判断 p − > n e x t p->next p−>next 和 q q q 的结点值是否相等,将 q q q 移动到与 p − > n e x t p->next p−>next 结点值不相等的位置。此时 q q q 没有移动,说明 q q q 和前一结点值不相等,使 p p p 后移即可 ; q q q 移动了,说明 q q q 的前一段有相等的结点,使 p − > n e x t = q p->next=q p−>next=q 即可。
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
auto dummy = new ListNode(-1);
dummy->next = head;
auto p = dummy ;
while(p->next){
auto q = p->next->next;
while(q&&q->val==p->next->val) q = q->next;
if(p->next->next==q) p = p->next;
else p->next = q;
}
return dummy->next;
}
};
时间复杂度: O ( n ) O(n) O(n) , n n n 是链表的长度,遍历链表的时间复杂度是 O ( n ) O(n) O(n) 。
空间复杂度: O ( 1 ) O(1) O(1) ,只使用了常量级空间。
//双指针, left right。
//设置哑结点,方便第一个元素的删除。
struct ListNode* deleteDuplicates(struct ListNode* head) {
struct ListNode* dummyHead = (struct ListNode*)calloc(1, sizeof(struct ListNode));//声明哑结点
dummyHead->next = head;
struct ListNode* left = dummyHead;//左指针从哑结点出发。
struct ListNode* right = head;//右指针从头结点出发。
if (NULL == right || NULL == right->next) {//空链表和单元素链表,返回头结点即可
return head;
}
right = right->next;//right领先left两个位置
while (right) {//右指针非空
int x = right->val;
if (x == left->next->val) {//一旦删除结点,结点就不后移了。
while (left->next&&left->next->val == x) {//left->next非空,right的val和right左一位的val相同
struct ListNode* temp = left->next;//待删除结点
left->next = right;//删除temp
temp->next = NULL;//避免野指针
free(temp);//释放被删除结点的空间
if(!right){//right为空
continue;//避免执行下一步,否则异常。
}
right = right->next;
continue;//检测新的left->next是否删除
}
continue;//在删除结点后,不能执行下一步,避免错过新的right。
}
left = left->next, right = right->next;//没有删除操作,左右指针右移一位。
}
return dummyHead->next;//哑结点目的,即是作为答案返回。
}
时间复杂度: O ( n ) O(n) O(n) , n n n 是链表的长度,一次遍历链表的时间复杂度是 O ( n ) O(n) O(n) 。
空间复杂度: O ( 1 ) O(1) O(1) ,只使用了常量级空间。