编写代码,移除未排序链表中的重复节点。保留最开始出现的节点。
示例1:
输入:[1, 2, 3, 3, 2, 1] 输出:[1, 2, 3]
示例2:
输入:[1, 1, 1, 1, 2] 输出:[1, 2]
提示:
- 链表长度在[0, 20000]范围内。
- 链表元素在[0, 20000]范围内。
进阶:
如果不得使用临时缓冲区,该怎么解决?
这道题我一开始的思路新建一个链表,直接遍历判断链表是否存在当前遍历到的值,若未遍历到,则存入新的链表,若存在,则判断下一个值
leetcode代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* removeDuplicateNodes(ListNode* head) {
// 如果链表为空,则直接返回nullptr,因为没有节点需要处理
if(head == nullptr){
return head;
}
// 声明一个哈希表(unordered_set),用于存储已经出现过的节点值
// 初始时将头结点的值插入哈希表,因为头结点总是需要保留的(除非它是重复的,但这种情况在题目中未明确说明如何处理)
unordered_set<int> occurred = {head->val};
// pos指针用于遍历链表,初始时指向头结点
ListNode* pos = head;
// 遍历链表,直到pos的下一个节点为空(即链表末尾)
while(pos->next != nullptr){
// cur指针指向pos的下一个节点,即当前正在检查的节点
ListNode* cur = pos->next;
// 如果cur节点的值没有出现在哈希表中,说明它不是重复节点
if(!occurred.count(cur->val)){
// 将cur节点的值添加到哈希表中,表示该值已经出现过
occurred.insert(cur->val);
// 移动pos指针到下一个节点,继续检查
pos = pos->next;
}else{
// 如果cur节点的值是重复的,则删除该节点
// 通过将pos的next指针指向cur的next指针,实现跳过cur节点
pos->next = pos->next->next;
// 注意:这里不需要移动pos指针,因为pos的下一个节点(即原来的cur节点)已经被删除了
}
}
// 注意:在遍历结束后,pos指针会指向链表的最后一个非重复节点
// 由于链表末尾的next指针应该为nullptr,所以这里显式地将pos的next指针设置为nullptr
// 这一步其实是多余的,因为在遍历过程中,如果链表末尾的节点不是重复的,pos最终会指向它,并且它的next已经是nullptr了
// 但为了代码的清晰性和完整性,还是保留这一行代码
pos->next = nullptr;
// 返回处理后的链表头结点
return head;
}
};
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
/**
* 移除链表中所有重复的节点,只保留原始节点链表中每个值第一次出现的节点。
* @param head 链表的头节点
* @return 移除重复节点后的链表的头节点
*/
ListNode* removeDuplicateNodes(ListNode* head) {
if (head == nullptr) {
// 如果链表为空,则直接返回nullptr
return nullptr;
}
ListNode* ob = head; // ob(outer block)用于遍历整个链表
while (ob != nullptr) {
ListNode* oc = ob; // oc(outer current)用于在ob指向的节点之后查找重复节点
while (oc->next != nullptr) {
// 如果发现oc的下一个节点的值与ob相同,则移除oc的下一个节点
if (oc->next->val == ob->val) {
oc->next = oc->next->next;
} else {
// 如果没有发现重复,则oc继续向后移动
oc = oc->next;
}
}
// 完成ob节点之后所有重复节点的移除后,ob向后移动
ob = ob->next;
}
return head; // 返回修改后的链表的头节点
}
};
因为问到不使用临时缓冲区,因此采用下面这种用时间换空间的做法。