【leetcode刷题记录】删除排序链表中的重复元素
题目描述1
给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字。
示例 1:
输入: 1->2->3->3->4->4->5
输出: 1->2->5
示例 2:
输入: 1->1->1->2->3
输出: 2->3
方法一
链表问题通常可以考虑用递归调用解决:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if(!head || !head->next) return head;
if(head->next && head->val == head->next->val){
while(head->next && head->val == head->next->val){
head = head->next;
}
return deleteDuplicates(head->next);
}
else{
head->next = deleteDuplicates(head->next);
}
return head;
}
};
方法二
用迭代的方法来实现常常是难点,本小白就在这里卡了很久,难度并不在于实现的思路,而在于指针的来回赋值很容易把人绕晕。
主要思路:
对于排序链表,从前往后遍历,将链表视为一个不重复的子链表和剩余链表两部分。用一个指针pre指向不重复子链表的末尾(用于删除元素操作中的连接操作),用一个指针p指向当前遍历数字的首个元素,再用一个指针q在p的基础上向后遍历。用一个bool repeat标识当前元素是否重复。
对于p所指的当前元素,首先通过q=p->next与其之后的一个元素比较,
-
若不重复,则该元素归入不重复子链表,将pre指向该元素,然后p=p->next继续向后遍历;
-
若重复,则q向后遍历,直到到遍历到第一个不等于p的元素或到达链表末尾。
- 此时进行删除操作,pre->next=q;
- 若pre为nullptr,说明表头元素重复,则直接将head=q;
- 最后将p=q,继续对下一个元素进行判断。
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
ListNode* pre=nullptr;
ListNode* p=head;
ListNode*q=nullptr;
bool repeat;
while(p){
q=p->next;
repeat=false;
if(q&&q->val==p->val)
repeat=true;
if(!repeat){
pre=p;
p=p->next;
}
else{
while(q&&q->val==p->val)
q=q->next;
if(pre==nullptr)
head=q;
else
pre->next=q;
p=q;
}
}
return head;
}
};
题目描述2
给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。
示例 1:
输入: 1->1->2
输出: 1->2
示例 2:
输入: 1->1->2->3->3
输出: 1->2->3
方法一
递归调用:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if(!head || !head->next) return head;
if(head->next && head->val == head->next->val){
while(head->next && head->val == head->next->val){
head = head->next;
}
}
head->next = deleteDuplicates(head->next);
return head;
}
};
方法二
利用双指针,循环迭代的方法。对于排序链表,从前往后遍历,将链表视为一个不重复的子链表和剩余链表两部分。用一个指针p指向不重复子链表的末尾(用于删除元素操作中的连接操作),head指针在遇到重复元素时向后找到第一个不再重复的元素的前一个元素,将p->next指向head->next,相当于把中间重复的部分直接删去,再p,head同时向后遍历直到再次遇到重复元素执行相同的操作。代码如下:
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
ListNode *p, *q;
p = head;
q = head;
int same = 0;
while(head){
while(head->next && head->val == head->next->val){
head = head->next;
same = 1;
}
if(same){
p->next = head->next;
same = 0;
}
head = head->next;
p = p->next;
}
return q;
}
};