编写代码,移除未排序链表中的重复节点。保留最开始出现的节点。
示例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; // 返回修改后的链表的头节点 }
};
因为问到不使用临时缓冲区,因此采用下面这种用时间换空间的做法。