【408DS算法题】023提高-判断带头结点的链表是否对称

题目

基础:给定链表的头结点,判断双循环链表是否对称。

提高:给定链表的头结点,判断单链表是否对称。


分析实现

首先分析基础题目:双循环链表的对称判断

下面分析提高题目:双循环链表的对称判断

具体实现如下:



总结

以上内容稍后补全,以下内容来自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 <vector>
#include <cmath>
// 链表结点的定义
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依旧存在。

  • 16
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值