题目
用单链表保存m个整数,结点的结构为 ( d a t a , l i n k ) (data,link) (data,link),且 ∣ d a t a ∣ < n ( n 为 正 整 数 ) |data|<n(n为正整数) ∣data∣<n(n为正整数)。现要求设计一个时间复杂度尽可能高效地算法,对于链表中绝对值相等的节点,仅保留第一次出现的结点而删除其余绝对值相等的结点。
例如若给定的单链表
h
e
a
d
head
head如下:
h
e
a
d
−
>
[
头
结
点
]
−
>
[
21
]
−
>
[
−
15
]
−
>
[
−
15
]
−
>
[
−
7
]
−
>
[
15
]
head->[头结点]->[21]->[-15]->[-15]->[-7]->[15]
head−>[头结点]−>[21]−>[−15]−>[−15]−>[−7]−>[15]
删除结点后的
h
e
a
d
head
head为:
h
e
a
d
−
>
[
头
结
点
]
−
>
[
21
]
−
>
[
−
15
]
−
>
[
−
7
]
head->[头结点]->[21]->[-15]->[-7]
head−>[头结点]−>[21]−>[−15]−>[−7]
要求
- 给出算法的基本思想
- 使用C或C++语言,给出单链表结点的数据类型定义
- 根据设计思想,采用C或C++语言描述算法,关键之处给出注释
- 说明所涉及算法的时间复杂度和空间复杂度
思路
单链表结点的数据类型定义如下:
typedef struct Node{
int data;
struct Node* link;
}Node,*LinkList;
依次取单链表中的每个结点作为标准,查找是否存在绝对值相等的结点,找到则执行删除结点操作,故建立两重循环,具体实现如下:
int get_val(int x){
//取绝对值
return x>0?x:-x;
}
LinkList delete_repeated_node(LinkList head){
Node *p=head->link;
while(p){//以p为标准,判断后方是否有结点与p的绝对值相等
Node *last=p,*tmp=p->link;
while(tmp){//用tmp指针遍历到链表尾,last指向tmp前一个结点
if(get_val(tmp->data)==get_val(p->data)){
//找到绝对值相等的结点,删除tmp结点
last->link=tmp->link;
delete tmp;
tmp=last->link;
}
else{//当前结点绝对值与p不等,后移到下一个
last=last->link;
tmp=tmp->link;
}
}
p=p->link;
}
return head->link;//单链表head包含头结点
}
此处由于用了两重循环,时间复杂度为 O ( n 2 ) O(n^2) O(n2),但未申请额外空间,故空间复杂度为 O ( 1 ) O(1) O(1)
另一种思路
遍历时,用一个集合记录结点的绝对值,每访问一个结点,判断其绝对值在集合中是否出现过。若出现过则删除结点,未出现过则将绝对值加入集合。
LinkList delete_repeated_node(LinkList head) {
set<int> s;
Node* p = head->link, * last = head;
while (p) {
if (s.find(get_val(p->data)) == s.end()) {
//不是绝对值重复出现的结点
s.insert(get_val(p->data));
p = p->link;
last = last->link;
}
else {
//绝对值重复,删除该结点
last->link = p->link;
delete p;
p = last->link;
}
}
return head->link;
}
时间复杂度为 O ( n ) O(n) O(n),空间复杂度为 O ( n ) O(n) O(n)