开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 19 天,点击查看活动详情
Day47 2023/02/22
难度:简单
题目
示例
输入:21 -15 -15 -7 15
输出:21 -15 -7
说明:对链表中绝对值相等的节点进行去重之后
思路
本题最直接的方式是用哈希法解题,遍历链表并用一个map去记录当前元素是否是第一次出现,如果是的话就让map记录下该节点并继续向后遍历,否则删除该节点。
具体步骤:
- 遍历链表,从虚拟头节点开始,每次判断下一个节点是否是首次出现,利用
record[val] == 0如果满足则该节点是首次出现,继续向下遍历,否则删除该节点。
关键点
- 其中哈希数组中,key为链表的数据,value为0或者1,用来判断该节点是否为第一次出现
- while的判断条件为cur->next 是因为每次判断的是下一个节点是否是重复节点,且
val =abs(cur->next->date)防止空指针异常。 - 每次判断的是下一个节点是否是重复节点,是因为这样可以保留判断节点的前驱节点,利于删除。
算法实现
c++代码实现-哈希法
#include <cmath>
#include <iostream>
#include <unordered_map>
using namespace std;
// 定义链表节点
typedef struct LNode {
int date;
LNode* next;
LNode(int val) : date(val), next(nullptr){};
} LNode, *LinkList;
/**
* @function 带虚拟头结点的尾插法创建单链表
* @param num 整型 链表长度
* @return LinkList 结构体 一个链表
*/
LinkList ListTailInsert(int num) {
LNode *dummyHead = new LNode(-1), *r = dummyHead, *s, *tmp; // 虚拟头节点 尾指针 待插入节点指针 临时指针
int i = 1, val = -1; // 辅助打印变量 待插入节点的数据
while (num-- && cin >> val) {
// cout << "请输入第" << i++ << "个节点元素值:" << endl;
// cin >> val;
s = new LNode(val);
r->next = s;
r = s;
}
cout << "单链表创建完毕!!!" << endl;
// tmp = dummyHead->next;
// delete dummyHead;
return dummyHead; // 返回虚拟头节点
}
/**
* @function 对链表中绝对值相等的节点进行去重,仅保留第一次出现的节点
* @param LinkList 结构体 一个链表
* @param n 整型
*/
void DeWeightToAbs (LinkList& L) {
LNode *cur = L, *tmp; // 遍历指针 临时指针
unordered_map<int, int> record; // 记录数组
while(cur->next) {
int val = abs(cur->next->date); // 节点数据
if (record[val] == 0) { // 等于0代表该节点未出现过,这是第一次出现
record[val] = 1;
cur = cur->next;
} else {
tmp = cur->next; // 重复节点
cur->next = cur->next->next; // 删除节点前,先修改next域,防止断链
delete tmp; // 删除该重复出现的节点
}
}
}
// 测试一下
int main() {
// 创建链表 测试数据 (21 -15 -15 -7 15)
LinkList L = ListTailInsert(5); // 不包括虚拟头节点
DeWeightToAbs(L); // 删除重复元素
LNode* cur = L->next; // 遍历指针
cout << "删除重复值后的链表:";
while (cur){
cout << cur->date << ' ';
cur = cur->next;
}
return 0;
}
- 时间复杂度 --- 遍历整个链表,其中n为链表节点个数
- 空间复杂度 --- 最坏情况下,该链表无重复节点,record的空间就等于链表节点个数n
总结
- 快速判断某个集合中是否含有该元素,一般都使用哈希!!!