leetcode 链接:移除重复节点
《程序员面试代码指南》by 左程云 中相同题目:★☆☆☆删除无序列表中值重复出现的节点

题目

编写代码,移除未排序链表中的重复节点。保留最开始出现的节点。

示例:

  1. 输入:[1, 2, 3, 3, 2, 1]
  2. 输出:[1, 2, 3]
  3. 输入:[1, 1, 1, 1, 2]
  4. 输出:[1, 2]

解答 & 代码

方法一:哈希表

使用额外的存储空间——哈希表,时间复杂度为 O(N),额外空间复杂度为 O(N)

方法:遍历链表节点

  • 如果该节点的值在哈希表中存在,则删除该节点
  • 如果该节点的值在哈希表中不存在,则将该值插入哈希表

注:对于链表,为了避免一些 bug,可以增加一个虚拟头节点,即 dummyHead

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */

#include <unordered_set>

class Solution {
public:
    ListNode* removeDuplicateNodes(ListNode* head) {
        unordered_set<int> valMap;

        ListNode* dummyHead = new ListNode(0);    //虚拟头节点
        dummyHead->next = head;

        ListNode* cur = dummyHead->next;
        ListNode* pre = dummyHead;
        while(cur != NULL)
        {
            if(valMap.find(cur->val) != valMap.end())
            {
                pre->next = cur->next;
                delete cur;
                cur = pre->next;
            }
            else
            {
                valMap.insert(cur->val);
                pre = cur;
                cur = cur->next;
            }
        }
        return dummyHead->next;
    }
};

执行结果:

执行结果:通过

执行用时:48 ms, 在所有 C++ 提交中击败了 38.75% 的用户
内存消耗:16.3 MB, 在所有 C++ 提交中击败了 31.12% 的用户

方法二:暴力解法(时间换空间)

不使用额外的空间,时间复杂度为 O([简单] 2.1 移除重复节点 - 图1),额外空间复杂度为 O(1)

遍历链表的节点,设当前遍历到的节点为 cur

  • 遍历 cur 节点之前的节点
    • 如果有等值节点存在,说明 cur 节点是重复节点,应删除
    • 否则,cur = cur->next ```cpp /**
      • 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) { ListNode* dummyHead = new ListNode(0); dummyHead->next = head;

    ListNode* cur = dummyHead->next;
    ListNode* pre = dummyHead;
    while(cur != NULL)
    {
        // 遍历当前节点之前的节点,判断当前节点是否为重复节点
        ListNode* left = dummyHead->next;
        while(left != cur && left->val != cur->val)
        {
            left = left->next;
        }

        if(left != cur) // 说明前面有该值的节点,即当前节点为重复节点,应删除
        {
            pre->next = cur->next;
            delete cur;
            cur = pre->next;
        }
        else            // 当前节点不是重复节点
        {
            pre = cur;
            cur = cur->next;
        }
    }
    return dummyHead->next;
}

};

执行结果:

执行结果:通过

执行用时:500 ms, 在所有 C++ 提交中击败了 7.38% 的用户 内存消耗:14.9 MB, 在所有 C++ 提交中击败了 73.22% 的用户 ```