题目
- 原文:
Write code to remove duplicates from an unsorted linked list.
FOLLOW UP
How would you solve this problem if a temporary buffer is not allowed? - 译文:
从一个未排序的链表中删除重复结点。
进一步地,
如果不允许使用临时的额外内存,你如何解决这个问题?
分析
emmm和之前做过的字符串中删除重复字符方法类似。
- 如果可以使用额外空间的话,与字符串不同的是字符串个数非常有限(256个),可以创建一个长度固定的数组来记录是否重复出现。而实数的个数是无限的还可以非负用数组位数来记录显然是不可行的,从负无穷到正无穷,单int所能表示的整数个数就有2^32之多,所以这里考虑采用map来记录出现过的结点,这样时间复杂度是O(n)。
- 如果不允许使用任何额外空间的话,只能通过循环比较的方法,需要两个指针,当第一个指针指向某个结点时,第二个指针从该结点向后遍历,将与它相同的结点都删除,
时间复杂度O(n^2 )。
代码
#include<iostream>
#include<cstring>
#include<map>
using namespace std;
typedef struct list {
int data;
list* next;
}list;
list* init(int a[], int n) {
list *head, *last;
for(int i= 0; i < n; i++) {
list* node = new list;
node->data = a[i];
if(i == 0) {
head = node;
last = node;
}
else {
last->next = node;
last = node;
}
if(i == n-1) {
node->next = NULL;
}
}
return head;
}
//Map方式,时间复杂度O(n)
void removelistdup1(list* head) {
map<int, bool> dupnum;
list *p = head, *q = head->next;
dupnum.insert(map<int, bool>::value_type(p->data, true));
while(q) {
if(dupnum.find(q->data) != dupnum.end()) {
list* temp = q;
p->next = q->next;
q = p->next;
delete temp;
}
else {
dupnum.insert(map<int, bool>::value_type(q->data, true));
p = q;
q = q->next;
}
}
}
//无额外内存记录方式,时间复杂度O(n^2)
void removelistdup2(list* head) {
list *p = head;
while(p) {
list *last = p, *q = p->next;
while(q) {
if(p->data == q->data) {
list* temp = q;
last->next = q->next;
q = q->next;
delete temp;
}
else {
last = q;
q = q->next;
}
}
p = p->next;
}
}
void printlist(list* head) {
while(head) {
cout << head->data << " ";
head = head->next;
}
}
int main() {
int a[] = {1,2,2,3,-1,1,4,5,-1};
int n = 9;
list* head = init(a,n);
//removelistdup1(head);
removelistdup2(head);
printlist(head);
}