知识点链表
描述
给出一个升序排序的链表,删除链表中的所有重复出现的元素,只保留原链表中只出现一次的元素。
例如:
给出的链表为, 返回.
给出的链表为, 返回.
数据范围:链表长度 ,链表中的值满足 要求:空间复杂度 ,时间复杂度 进阶:空间复杂度 ,时间复杂度
示例1
输入:
{1,2,2}
返回值:
{1}
示例2
输入:
{}
返回值:
{}
题解
使用计数器的解法
思路:
遍历整个链表,使用一个计数器对重复的节点进行计数,如果节点个数是1则加入链表中,实现如下:
struct ListNode
{
int val;
struct ListNode *next;
ListNode(int x) : val(x), next(nullptr)
{
}
ListNode() = default;
};
ListNode *deleteDuplicates(ListNode *head)
{
if (head == nullptr || head->next == nullptr)
{
return head;
}
ListNode *first_node = nullptr;
ListNode *tail_node = nullptr;
ListNode *cur_node = head;
int count = 1;
while (cur_node != nullptr)
{
if (cur_node->next == nullptr)
{
if (count == 1)
{
if (first_node == nullptr)
{
first_node = cur_node;
first_node->next = nullptr;
}
else
{
tail_node->next = cur_node;
}
}
else
{
if (tail_node != nullptr)
{
tail_node->next = nullptr;
}
}
break;
}
else
{
auto next_node = cur_node->next;
if (cur_node->val == next_node->val)
{
count++;
cur_node = next_node;
}
else
{
if (count == 1)
{
if (first_node == nullptr)
{
first_node = cur_node;
tail_node = cur_node;
tail_node->next = nullptr;
}
else
{
tail_node->next = cur_node;
tail_node = tail_node->next;
}
}
count = 1;
cur_node = next_node;
}
}
}
return first_node;
}
使用快慢指针的解法
- 思路:双指针:fast探测并跳过重复的节点,slow指向已检查过的最后一个,使用slow->next = fast删除重复的节点
- 难点:头节点也可能要删除。这里往头部之前加一个虚拟头部vhead,让slow先指向vhead
ListNode *deleteDuplicates(ListNode *head)
{
ListNode *vHead = new ListNode(0);
vHead->next = head;
ListNode *fast = head;
ListNode *slow = vHead;
while (fast && fast->next)
{
if (fast->next->val != fast->val)
{ //检测fast指向的节点是否重复
slow = fast; //不重复,slow往前一步
fast = fast->next;
}
else
{
int repeatVal = fast->val; //记录重复的值,让fast跳过全部值相同的节点
while (fast && fast->val == repeatVal)
{
fast = fast->next;
}
slow->next = fast; //注意此时fast指向的节点仍可能重复,所以slow不动
}
}
return vHead->next;
}