当前位置: 首页 > article >正文

链表拆分与快慢指针相关算法题

一拆分为二

C = a 1 , b 1 , a 2 , b 2 , … , a m , b m C={a_{1},b_{1},a_{2},b_{2},\dots,a_{m},b_{m}} C=a1,b1,a2,b2,,am,bm,为线性表,采用带头节点的单链表存放,将其拆分为两个线性表
使得 A = a 1 , a 2 , … , a n A=a_{1},a_{2},\dots,a_{n} A=a1,a2,,an B = b n , … , b 2 , b 1 B=b_{n},\dots,b_{2},b_{1} B=bn,,b2,b1

算法思想

循环遍历链表C,
采用尾插法将一个节点插入表A,这个节点为奇数号节点,这样建立的表A与原来的节点顺序相同;
采用头插法将下一节点插入表B,这个节点为偶数号节点,这样建立的表B与原来的节点顺序正好相反
![[Pasted image 20241106204401.png]]

malloc一个B头节点,将B的next指向NULL
![[Pasted image 20241106204918.png]]

用一个工作指针cur来指向A表的第一个节点,准备遍历A表
用一个tail指针指向A头节点,用来尾插找尾
cur往后遍历A表,直到cur指向空时结束
![[Pasted image 20241106205224.png]]

将tail的next也就是A的next指向cur,这里不动
![[Pasted image 20241106205257.png]]

tail指针后移,指向A表的最后一个节点
![[Pasted image 20241106205326.png]]

cur指向cur的next,后移一位
这时候cur走向偶数位置,判断cur是否指向空
用next保存cur的下一个节点
![[Pasted image 20241106205457.png]]

cur的next指向B的next,将cur头插到B表
![[Pasted image 20241106205601.png]]

B的next指向cur
![[Pasted image 20241106205626.png]]

cur指向next
![[Pasted image 20241106205647.png]]

再进行A表的尾插
![[Pasted image 20241106205815.png]]

再进行B表的头插
![[Pasted image 20241106205842.png]]

将tail的next指向NULL
![[Pasted image 20241106210017.png]]

LinkList DisCreat(LinkList &A)
{
	LinkList B = (LinkList)malloc(sizeof(LNode));  //创建B表表头
	B->next = NULL;     //B表初始化
	LNode* cur = A->next, *next;  //cur为工作指针
	LNode* tail = A;         //tail始终指向A的尾节点
	while (cur)
	{
		tail->next = cur;    //将*cur链到A的表尾
		tail = cur;
		cur = cur->next;
		if (cur)
		{
			next = cur->next;  //头插后,*cur将断链,用next记忆*cur的后继
			cur->next = B->next;  //将*cur插入到B表的前端
			B->next = cur;
			cur = next;
		}
	}
	tail->next = NULL;    //A尾节点的next指向NULL
	return B;
}

判断链表是否带环

单链表有环,是指单链表的最后一个节点的指针指向了链表中的某个节点,判断单链表是否存在环

算法思想

设置快慢指针分别为fast和slow最初都指向链表头head
slow每次走一步,fast每次走两步
fast走得比slow快,若有环,则fast一定先进入环
两个指针进入环后,一定会在环上相遇
链表分割|链表的回文结构|相交链表|环形链表|随机链表的复制©-CSDN博客
这里有详细说明过程,环形链表1和2
![[Pasted image 20241106221440.png]]

LNode* FindLoopStart(LNode* head)
{
	LNode* fast = head, *slow = head;  //设置两个快慢指针
	while (fast && fast->next)
	{
		slow = slow->next;             //每次走一步
		fast = fast->next->next;       //每次走两步
		if (slow == fast)              //相遇
			break;
	}
	if (fast == NULL || fast->next == NULL)
		return NULL;                   //没有环,返回空
	LNode* p1 = head, *p2 = slow;      //分别指向开始点,相遇点
	while (p1 != p2)
	{
		p1 = p1->next;
		p2 = p2->next;
	}
	return p1;                         //返回入口点
}

一个指针从头节点开始走,一个节点从相遇点开始走,当两个指针相遇的时候,就是入口点

返回倒数第k个节点

输入一个链表,输出该链表的倒数第k个节点

算法思想

快慢指针思想
将fast指针指向链表的第k+1个节点,slow指向链表的第一个节点,此时fast和slow之间刚好相差k个节点,两个指针同步向后走,当fast走到链表的尾部空节点时,slow指针正好指向链表的倒数第k个节点
![[Pasted image 20241106225844.png]]

fast先走k步,之后同步走
![[Pasted image 20241106225922.png]]

直到fast指向空
![[Pasted image 20241106230012.png]]

LNode* getKthFromEnd(LinkList &head, int k)
{
	if (head == NULL)
		return NULL;
	LNode* fast = head, *slow = head;
	int i = 0;
	while (fast)
	{
		if (i >= k)
		{
			slow = slow->next;
		}
		fast = fast->next;
		i++;
	}
	return slow;
}

http://www.kler.cn/a/382717.html

相关文章:

  • C++入门基础知识134—【关于C 库函数 - gmtime()】
  • 【MWorks】Ubuntu 系统搭建
  • 跨平台Flutter 、ReactNative 开发原理
  • 【Linux系列】利用 CURL 发送 POST 请求
  • 网站504错误出现的原因以及如何修复
  • 使用 AMD GPU 的 ChatGLM-6B 双语语言模型
  • 算法时间复杂度和真实时间测算
  • 枚举,联合(共用体)
  • 前后端跨域联调
  • SpringBooot之事务失效的场景
  • 护肤品类电商代运营的公司介绍与分析
  • 【Docker】X-DOC:使用WSL在Windows中体验Linux发行版安装桌面版Docker
  • 在 MacOS 上跑 kaldi
  • Java+控制台 商城销售系统
  • 【动态规划 数学】2745. 构造最长的新字符串|1607
  • Web Workers 学习笔记
  • 【QT】Qt文件和多线程
  • SSLHandshakeException错误解决方案
  • Flutter常用命令整理
  • Halcon 矫正图像 图像矫正
  • CustomDataSource、Entity 和 Primitive 区别
  • MongoDB笔记02-MongoDB基本常用命令
  • 小程序 + AI 自动直播:一部手机开启抖音挂载小程序流量主变现之旅
  • 搭建react项目
  • Markdown转HTML
  • 前深度学习时代-经典的推荐算法