408真题-2015年链表绝对值节点删除

122 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 19 天,点击查看活动详情

Day47 2023/02/22

难度:简单

题目

image.png

示例

输入:21 -15 -15 -7 15
输出:21 -15 -7 
说明:对链表中绝对值相等的节点进行去重之后

思路


本题最直接的方式是用哈希法解题,遍历链表并用一个map去记录当前元素是否是第一次出现,如果是的话就让map记录下该节点并继续向后遍历,否则删除该节点。
具体步骤:

  1. 遍历链表,从虚拟头节点开始,每次判断下一个节点是否是首次出现,利用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;
 }
  • 时间复杂度 O(n)O(n) --- 遍历整个链表,其中n为链表节点个数
  • 空间复杂度 O(n)O(n) --- 最坏情况下,该链表无重复节点,record的空间就等于链表节点个数n

总结

  • 快速判断某个集合中是否含有该元素,一般都使用哈希!!!