PAT L2-002. 链表去重 巧妙利用数组的索引

本文介绍了一种针对带有整数键值的单链表进行去重处理的方法,具体包括了如何保留首次出现的节点并移除重复键值的节点,同时记录被删除的节点。通过使用标志数组来跟踪键值的首次出现,最终输出去重后的链表及被删除的链表。
给定一个带整数键值的单链表L,本题要求你编写程序,删除那些键值的绝对值有重复的结点。即对任意键值K,只有键值或其绝对值等于K的第一个结点可以被保留。同时,所有被删除的结点必须被保存在另外一个链表中。例如:另L为21→-15→-15→-7→15,则你必须输出去重后的链表21→-15→-7、以及被删除的链表-15→15。


输入格式:


输入第一行包含链表第一个结点的地址、以及结点个数N(<= 105 的正整数)。结点地址是一个非负的5位整数,NULL指针用-1表示。


随后N行,每行按下列格式给出一个结点的信息:


Address Key Next


其中Address是结点的地址,Key是绝对值不超过104的整数,Next是下一个结点的地址。


输出格式:


首先输出去重后的链表,然后输出被删除结点组成的链表。每个结点占一行,按输入的格式输出。


输入样例:
00100 5
99999 -7 87654
23854 -15 00000
87654 15 -1
00000 -15 99999
00100 21 23854
输出样例:
00100 21 23854
23854 -15 99999
99999 -7 -1
00000 -15 87654

87654 15 -1

思路:此题目理解起来不难,关键是模拟,如何判断第一个键值是否被访问呢?  flag[abs(a[s].key)],是第一次访问的存入一个数组,不是则存入另一个数组,存入的仅为索引,从始至终,这份代码都只利用刚开始结构体的索引来解决,第一次见到题目我还以为要用set来构造

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int N=1e5+5;
struct node
{
   int inext;
   int key;
}a[N];//数组的索引即为Address
int ex[N];
int de[N];
int flag[N];

int main()
{
    int s,n,p;
    int exi=0,del=0;
    cin>>s>>n;
    for(int i=1;i<=n;i++){
        cin>>p;
        cin>>a[p].key>>a[p].inext;
    }
    memset(flag,0,sizeof(flag));
    for(int i=0;i<n&&s!=-1;i++){
        if(!flag[abs(a[s].key)]){ //查询键值是否为第一次访问
          ex[exi++]=s;
          flag[abs(a[s].key)]=1;
          s=a[s].inext;
        }else
        {
            de[del++]=s;
            s=a[s].inext;
        }
    }
     if(exi){
        for(int i=0;i<exi;i++){
            if(i==0){
                printf("%05d %d",ex[i],a[ex[i]].key);
            }
            else{
                printf(" %05d\n%05d %d",ex[i],ex[i],a[ex[i]].key);
            }
        }
        printf(" -1\n"); //最后的-1 表示
    }
    if(del){
        for(int i=0;i<del;i++){
            if(i==0){
                printf("%05d %d",de[i],a[de[i]].key);
            }
            else{
                printf(" %05d\n%05d %d",de[i],de[i],a[de[i]].key);
            }
        }
        printf(" -1\n");
    }
}

### 关于链表的算法实现 对于链表问题,可以采用哈希集合来记录已经遇到的绝对值键值。遍历整个链表的过程中,如果发现当前节点的绝对值已经在集合中存在,则该节点应被移除并加入到新的链表中;反之则将其保留。 为了高效处理这一过程,在C++环境下可利用`std::unordered_set<int>`作为辅助工具,并定义两个指针分别追踪原链表和待删除节点形成的链表的位置变化情况[^1]。 下面给出具体的代码示例: ```cpp #include <iostream> #include <unordered_set> using namespace std; struct ListNode { int val; ListNode *next; ListNode(int x) : val(x), next(nullptr) {} }; void removeDuplicates(ListNode*& head, ListNode*& removedHead) { unordered_set<int> seenAbsValues; ListNode dummy(0); dummy.next = head; ListNode* prev = &dummy; removedHead = nullptr; ListNode* removedTail = nullptr; while (prev->next != nullptr){ int absVal = abs(prev->next->val); if (!seenAbsValues.insert(absVal).second){ // 如果插入失败说明已存在相同abs value auto tempNode = prev->next; // 记录要删除的节点 prev->next = prev->next->next; // 跳过这个节点完成删除操作 tempNode->next = nullptr; if(!removedHead){ removedHead = tempNode; removedTail = tempNode; } else{ removedTail->next = tempNode; removedTail = removedTail->next; } }else{ prev = prev->next; } } } ``` 此函数接收原始链表头部以及用于存储已被删除节点的新链表头部作为参数。通过引入哑元节点简化边界条件判断逻辑,确保即使当列表为空或仅含单个元素时也能正常工作。此外,借助STL中的容器类库——无序集合作为快速查找结构,实现了O(n)时间复杂度下的线性扫描复项功能[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值