面试题02.01 移除重复节点
编写代码,移除未排序链表中的重复节点。保留最开始出现的节点。
示例1:
输入:[1, 2, 3, 3, 2, 1]
输出:[1, 2, 3]
示例2:
输入:[1, 1, 1, 1, 2]
输出:[1, 2]
提示:
链表长度在[0, 20000]范围内。
链表元素在[0, 20000]范围内。
解题思路:
1.哈希表,空间换时间
注意到题目给的是未排序的链表,因此,需要考虑的情况也就更为复杂。首先想到的是使用一个哈希表来记录已出现的val值,如果当前位置cur的val值已经在哈希表中存在,则该节点需要被删去。
需要格外考虑的是,在单链表中,若想删除当前节点,我们需要知道当前节点之前的链表节点。才能用pos->next=cur->next来执行删除操作。
/**
* 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) {
//边界情况
if(head==nullptr)
return head;
unordered_set<int> occurred={head->val};
ListNode *pos=head;
while(pos->next!=nullptr){
ListNode* cur=pos->next;
if(!occurred.count(cur->val)){
occurred.insert(cur->val);
pos=cur;
}
else{
pos->next=cur->next;
}
}
pos->next=nullptr;
return head;
}
};
时/空复杂度
时间复杂度:只需一次遍历,便可完成任务,因此为时间复杂度O(n)。
空间复杂度: 额外开辟了辅助空间来存储已出现过得元素值,因此空间复杂度为O(n)。
2.暴力法,时间换空间
如果不使用额外空间,想要保持时间复杂度为O(n)是不现实的,因此,使用双重循环来解决问题,使用指针pos来记录一重循环当前链表位置值(pos需要保持不动,直到后续元素全部被遍历到),cur指针来记录二重循环中当前位置,用来对重复元素进行删除。
/**
* 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) {
if(head==nullptr)
return head;
ListNode *pos=head;
while(pos!=nullptr){
ListNode *cur=pos;
while(cur->next!=nullptr){
if(cur->next->val==pos->val)
cur->next=cur->next->next;
else
cur=cur->next;
}
pos=pos->next;
}
return head;
}
};
时/空复杂度:
时间复杂度:双重循环,时间复杂度为。
空间复杂度:没有用到额外空间,空间复杂度为O(1)。