【408DS算法题】024进阶-12年真题_找出两个链表的共同后缀的起始位置

Index

    • 真题题目 (以下内容来自https://blog.csdn.net/weixin_60702024/article/details/141370977)
    • 分析实现
      • 总结

真题题目 (以下内容来自https://blog.csdn.net/weixin_60702024/article/details/141370977)

用单链表保存 m个整数,结点的结构为[data][link],且 ∣ d a t a ∣ ⩽ n |data|\leqslant n datan(n为正整数)。
现要求设计一个时间复杂度尽可能高效的算法,对于链表中 data 的绝对值相等的结点,仅保留第一次出现的结点而删除其余绝对值相等的结点。例如,若给定的单链表 HEAD 如下:
HEAD -> [21] -> [15] -> [15] -> [-7] -> [15]^
则删除结点后的 HEAD 为
HEAD -> [21] -> [15] -> [-7]^
要求:

  1. 给出算法的基本设计思想。
  2. 使用 C 或 C++语言,给出单链表结点的数据类型定义。
  3. 根据设计思想,采用C或 C++语言描述算法,关键之处给出注释。
  4. 说明你所设计算法的时间复杂度和空间复杂度。

(本文重点关注算法实现及思路分析,不含具体答题表述)

分析实现

本题的大部分要求都很容易理解并运用,重点在于 ∣ d a t a ∣ ⩽ n |data|\leqslant n datan 这个条件。

与此条件之经常一同使用的是桶计数的思想——建立一个大小为n的数组have,每个数组元素记录一个数值的存在情况。如果当前数值已经存在,就删除当前结点;如果当前数组未出现过,就更新have,继续移动链表。

类似于【删除链表中最小结点】,在本题中也定义了指针pre记录当前节点的前驱结点以便于删除当前结点。
此外为书写简洁,本题指针的初始化和循环更新的逻辑也有一些习惯性的调整,具体解题时逻辑合理即可。

具体实现如下:

#include 
#include 
// 链表结点的定义
struct LNode {
    int data;
    LNode *link;
};

// 删除绝对值相同元素
void removeRep(LNode *head, int n){
	// 用布尔数组记录数值出现的情况,并初始化为0 - 表示未出现
	vector<bool> have(n+1, 0);

	LNode *pre = head, *cur;
	while(pre->link){
		cur = pre->link;
		// 当前节点的值已经出现过 - 删除当前节点
		if(have[abs(cur->data)]){
			pre->link = cur->link;
			delete cur;
		}
		// 当前节点的值未出现过 - 更新have数组,并移动pre指针
		else{
			have[abs(cur->data)] = 1;
			pre = cur;
		}
	}
}

总结

以上就是删除单链表中绝对值相同的点的代码实现。本题重在理解桶计数的思想,将元素的存在信息存入数组之中。

为方便表示,此处建立的是大小为n+1的数组来记录n个元素出现的情况,这样就可以令have[i]直接表示元素i的出现情况,更加容易将数组下标和元素进行对应。

此外要注意对删除的结点进行内存空间的释放,并理解delete cur;执行后,只会将指针指向内容的内存释放,但指针变量cur依旧存在。

你可能感兴趣的:(算法,链表,数据结构)