链表的经典问题

链表的经典问题

 

 

如何判断两个单链表是否相交,如果相交,找出交点(两个链表都不存在环)

如果两个单链表相交,那应该呈“Y”字形,也就是从交点以后的部分是两个链表的公共节点。

所以,判断是否相交只要看两个链表的最后一个节点是否为同一个即可。

那么如何找到交点呢?设两个单链表的长度分别为L1、L2,(假设L1>L2),则(L1-L2)的值就是交汇之前两个链表的长度差;

因此,只有让更长的链表先走L1-L2步,然后两个链表开始一起走,如果某次走到一个相同的节点,该节点即为交点。

 

C代码实现:

typedef struct _ListNode {int data;struct _ListNode *next;
} ListNode;static int GetListLength(ListNode *T) 
{int n;for(n=0; T; n++) {T = T->next; }   return n;
}static ListNode* FindFirstCommonNode(ListNode *T1, ListNode *T2)
{int i;int n1 = GetListLength(T1);int n2 = GetListLength(T2);// T1 always own longer listif (n1 < n2) {return FindFirstCommonNode(T2, T1);}   for (i=0; i<n1-n2; i++) {T1 = T1->next;}   while (T1 && T1 != T2) {T1 = T1->next;T2 = T2->next;    }   return T1; 
}

 

该问题还有一种思路,就是将其中一个链表首尾相连,然后检测另外一个链表是否有环,如果存在环,则两个链表相交。

 

判断一个链表是否有环,并找到环的入口点

如果一个单链表有环,那应该呈“6”字形。

设置两个指针(fast, slow),初始值都指向头节点,slow每次前进一步,fast每次前进二步,如果链表存在环,则fast必定先进入环,而slow后进入环,两个指针必定 相遇:如果链表是呈"O"字形,则slow刚好遍历完一次的时候,与fast相遇;如果呈“6”字形,则更早相遇。

当fast若与slow相遇时,slow还没有遍历完链表,而fast已经在环内循环了n圈(1<=n)。假设slow走了s步,则 fast走了2s步(fast步数还等于s 加上在环上多转的n圈),设环长为r,则:

2s = s + nr,简化为 s= nr

s = x + y,x为链表起点到环入口点的距离,y是slow在环内走过的距离;

可以得到 x = y - s = y - nr,从链表头、相遇点分别设一个指针(p1, p2),每次各走一步,当p1走过距离x时到达入口点,而p2走过的距离为y-nr,y是相遇点与入口点的距离,因此y也走到了入口点,也就是说p1、p2在环入口点相遇了。

 

C代码实现:

static ListNode* FindLoopPort(ListNode *Head)  
{  ListNode *slow = Head; ListNode *fast = Head;  // 找到相遇点while ( fast && fast->next ) {   slow = slow->next;  fast = fast->next->next;  if ( slow == fast ) break;  }   if (fast == NULL || fast->next == NULL)  return NULL;  // 找到环入口点slow = Head;  while (slow != fast)  {   slow = slow->next;  fast = fast->next;  }   return slow;  
}  

 

 

求一个单链表(无环)的中间节点

设置两个指针(fast, slow),初始值都指向头节点,slow每次前进一步,fast每次前进二步,当fast走到末尾时,slow刚好指向中间节点。

 

假如链表长度为N,如何返回链表的倒数第K个结点

思路:用两个指针,指针P1先走K-1步,然后指针P2才开始走,当指针P1遍历完链表时,P2还剩K个结点没有遍历。

 

实现如下:

ListNode *FindLastKNode(ListNode *Head, int K)
{if (NULL == Head)return NULL;ListNode *T1 = Head;ListNode *T2 = Head;while (T1 && --K) T1 = T1->next; if (K) // here, K must be 0 return NULL; while (T1->next) { T1 = T1->next; T2 = T2->next; } return T2; }

 

 

在O(1)时间删除链表结点

在链表中删除一个结点,最常规的做法是遍历链表,找到要删除的结点后再删除,这种做法的时间复杂度是O(n);
换一种思路,根据待删除结点A,可以知道其下一个结点是B=A->next,将结点B值拷贝给A,然后删除B即可。
这种方法需要考虑一种特殊情况,A如果是尾结点,则B不存在,此时仍需要遍历链表一次。

 

C代码实现:

void DeleteNode(ListNode* Head, ListNode *pDel)
{if (NULL == pDel || NULL == Head)return;ListNode *p = Head;if (NULL == pDel->next) {     // pDel is the last nodewhile (pDel != p->next)p = p->next;p->next = NULL;free(pDel);
}
else {p = pDel->next;pDel->next = p->next;pDel->data = p->data;free(p);} }

 

 

如何逆序输出一个单链表

方法一:从头到尾遍历链表,每经过一个结点的时候,把该结点放到一个栈中;当遍历完整个链表后,再从栈顶开始输出结点的值。
该方法需要维护一个额外的栈,实现起来比较麻烦。我们注意到递归本质上就是一个栈结构,所以,也可以用递归来实现反向输出链表。


方法二:也就是说,每访问到一个结点的时候,先递归输出它后面的结点,再输出该结点自身。

 

C代码实现:

void ReversePrint(ListNode *Head)
{if (Head) {if (Head->next) {ReversePrint(Head->next);}printf("%d ", Head->data);}
}

 

 

 

如何反转一个单链表

 利用辅助指针就地修改节点的next域,代码如下:

static ListNode *ReverseList(ListNode *Head)
{ListNode *pNode = Head;ListNode *pNext = NULL;ListNode *pPrev = NULL;while (pNode) {pNext = pNode->next;    if (NULL == pNext)     // meet the endHead = pNode;pNode->next = pPrev;pPrev = pNode;pNode = pNext;}   return Head;
}

 

递归 的实现方法:

static void ReverseList2(ListNode** Head)
{ListNode *p = *Head;if (!p) return;ListNode* rest = p->next;if (!rest) return;ReverseList2(&rest);rest->next = p;p->next = NULL;
}

 

 

链表的排序

归并排序实现的时间复杂度为 nlgn,

struct ListNode* Merge(struct ListNode* p1, struct ListNode *p2) {if (!p1) return p2;if (!p2) return p1;if (p1->val > p2->val) {p2->next = Merge(p1, p2->next);return p2;} else {p1->next = Merge(p1->next, p2);return p1;}}struct ListNode* sortList(struct ListNode* head) {if (!head || !head->next) return head;struct ListNode *h1, *h2;struct ListNode *p1 = head, *p2 = head, *p = head;while (p2 && p2->next) {p = p1;p1 = p1->next;p2 = p2->next->next;}p->next = NULL;h1 = sortList(p1);h2 = sortList(head);return Merge(h1, h2);
}

以上递归的实现会占用lgN的空间(递归压栈),非递归的实现如下:

 

 

复杂链表的复制

假设有一个复杂链表,它除了有一个next指针外,还有一个other指针,指向链表中的任一结点或者NULL,

typedef struct _ListNode {int data;struct _ListNode *next;struct _ListNode *other;
} ListNode;

 

如下图,是一个含义5个节点的该类型的复杂链表,实线表示next指针,虚线表示other指针,NULL指针未标出。

 

最简单的方法是,先复制所有节点,并用next指针链接起来,然后假设原始链表的某节点N的other指针指向节点S,由于S的位置可能在N的前面,也可能在N的后面,所以要定位N的位置需要从原始链表的头节点开始找,直到确认节点S在链表中的位置为s;然后在复制链表上节点N的other指针也要指向距离链表头的第s个节点。这种方法的时间复杂度是O(n2)。

上面这种方法的主要缺点在于无法快速定位N节点的other所指向的S节点的位置,

 

下面将介绍一种时间复杂度是O(n)的方法,首先把复制的节点串到原节点后面,如下图:

 

然后设置复制节点的other指针(例如 A'->other = A->other->next),如下图

最后,把偶数顺序的节点和奇数节点的指针分开。

 

// 逐个节点复制,并串到原节点后面
static void CloneNodes(ListNode *Head)
{ListNode *p = Head;while (p) {ListNode *pCloned = malloc(sizeof(ListNode));pCloned->data = p->data;pCloned->next = p->next;pCloned->other = NULL;p->next = pCloned;p = pCloned->next;}
}// 设置新节点的other指针
static void ConnectNodes(ListNode *Head)
{ListNode *pCloned;ListNode *p = Head;while(p){pCloned = p->next;if (p->other) {pCloned->other = p->other->next;}p = pCloned->next;}
}

 

转载于:https://www.cnblogs.com/chenny7/p/4113552.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/492719.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

亚马逊、谷歌和微软寸土必争的新战场

作者&#xff1a; Caroline Donnelly 编译&#xff1a;机器之能 张玺摘要&#xff1a;当亚马逊、谷歌与微软都表示要争取所有可能的垂直市场客户时&#xff0c;云服务三巨头在零售市场的竞争变得愈发有趣。云技术在零售市场应用方面表现抢眼&#xff0c;但是竞争问题正在影响客…

duilib环境配置以及简单入门介绍

内容全部为转载&#xff1a; VS2013的编译&#xff0c;https://www.cnblogs.com/Alberl/p/3342030.html duilib框架介绍&#xff0c;以及VS2013配置&#xff0c;创建工程&#xff0c;调试代码部分&#xff1a; https://blog.csdn.net/lanuage/article/details/52040306 https:/…

2019年汽车行业深度投资研究

来源&#xff1a;中泰证券2018年预计我国汽车销售负增长&#xff0c;为30年来首次&#xff0c;批发数据自5月份开始逐步下降&#xff0c;尤其是9月之后,销售增速加速下滑,判断汽车市场弱势的原因和持续时间长短&#xff0c;是思考2019年汽车行业投资策略的前提。我们认为&#…

有没有哪些数学猜想是验证到很大的数以后才发现是错的?

来源&#xff1a;孙天任算数学苑素数的分布密度为 ρ(x)~1/ln(x)&#xff0c;从而在 x 以内的素数个数——通常用 π(x) 表示——为&#xff1a; π(x) ~ Li(x) 其中 Li(x) ≡ ∫ 1/ln(x) dx 是对数积分函数 。这个结果有些读者可能也认出来了&#xff0c;它正是著名的素数定理…

徐铁:当深度学习握手脑科学-圣城会议归来

原创&#xff1a;许铁 来源&#xff1a;混沌巡洋舰耶路撒冷号称三教圣地&#xff0c; 而它的牛逼之处绝不仅在于宗教&#xff0c; 如果你深入了解&#xff0c; 你会发现它的科学&#xff0c;尤其是理论创新也同样牛逼&#xff0c; 尤其是在脑科学和人工智能方向。 当然神族…

重磅!联合国权威AI趋势报告,美中日韩四分天下

来源&#xff1a;智东西摘要&#xff1a;AI趋势报告&#xff0c;中美专利申请和科学出版数遥遥领先。近年来&#xff0c;随着AI从理论知识落地到全球市场&#xff0c;AI正以其潜在的革命性影响&#xff0c;持续推动技术和产业的重大变革&#xff0c;从天气预报、自动驾驶、癌症…

通信产业5G迭代,万亿机遇一触即发

来源&#xff1a;中银国际摘要&#xff1a;进入本世纪一零年代后&#xff0c;全球通信行业首先迎来了4G商用的元年。▌通信产业5G迭代促使中国企业突破进入本世纪一零年代后&#xff0c;全球通信行业首先迎来了4G商用的元年。LTE网络在世界各地开花&#xff0c;“管”领域的性能…

duilib中界面的布局方式

参考博客&#xff1a;https://blog.csdn.net/zhuhongshu/article/details/38531447 常用的布局默认为相对布局&#xff0c;默认floatfalse&#xff0c;该属性为true时&#xff0c;表示绝对布局&#xff1b; 相对布局方式可以依据界面自动调整控件大小。 最常用的VerticalLayout…

美丽新世界:这七个原因将让未来更美好

来源&#xff1a;资本实验室摘要&#xff1a;技术进步推动人类社会的进步。然而在现实生活中&#xff0c;对技术的恐惧困扰着相当一部分人。暴走的机器人、失控的AI、滥用的人体增强……这些经常出现于各种反乌托邦科幻故事中的场景也被认为是对技术破坏的一种警示。如果能够从…

学习OpenStack之 (4): Linux 磁盘、分区、挂载、逻辑卷管理 (Logical Volume Manager)

0. 背景&#xff1a; inux用户安装Linux操作系统时遇到的一个常见的难以决定的问题就是如何正确地评估各分区大小&#xff0c;以分配合适的硬盘空间。普通的磁盘分区管理方式在逻辑分区划分好之后就无法改变其大小&#xff0c;当一个逻辑分区存放不下某个文件时&#xff0c;这个…

写论文文献引用方式

打开百度学术&#xff1a; 如下&#xff1a;

美国DARPA204页可解释人工智能文献综述论文《Explanation in Human-AI Systems》

来源&#xff1a;专知摘要&#xff1a;本文介绍Arxiv上的《Explanation in Human-AI Systems》&#xff0c;一篇关于可解释机器学习的综述&#xff0c;介绍了可解释机器学习的多学科观点、历史研究、模型、关键点等。可解释AI是现在正火热的科研和工程问题。Arxiv上一篇《Expla…

BestCoder22 1003.NPY and shot 解题报告

题目链接&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid5144 题目意思&#xff1a;有个人抛物体&#xff0c;已知抛的速度和高度&#xff0c;问可以抛到的最远距离是多少。即水平距离。 做的时候是抄公式的&#xff0c;居然过了&#xff0c;幸运幸运............ 1 #…

37页PPT,全面解读5G产业链及未来趋势!

来源&#xff1a;国信证券经济研究所、全球物联网观察摘要&#xff1a;接下来的一年&#xff0c;5G无疑是全球关注的焦点。接下来的一年&#xff0c;5G无疑是全球关注的焦点。5G开始商用化&#xff0c;除了进一步促进移动互联网的发展&#xff0c;更重要的是会促进移动互联网和…

atoi简析

原文链接 atoi()函数的功能&#xff1a;将字符串转换成整型数&#xff1b;atoi()会扫描参数nptr字符串&#xff0c;跳过前面的空格字符&#xff0c;直到遇上数字或正负号才开始做转换&#xff0c;而再遇到非数字或字符串时&#xff08;\0&#xff09;才结束转化&#xff0c;并将…

盘点2018十大科技丑闻,IT相关两项

来源&#xff1a;科技日报2018这一年里&#xff0c;风起云涌的科技界很忙&#xff0c;有些人尝到了甜头&#xff0c;有些人却吃到了苦头&#xff0c;有些事件令人瞠目结舌、难以置信……   盘点2018年十大科技丑闻是为了更加清醒地看到科技发展过程中的不尽如人意。  更重要…

QT安装和Hello,world

QT安装环境介绍&#xff1a; https://blog.csdn.net/hechao3225/article/details/52981007 教程&#xff1a; http://c.biancheng.net/qt/ Hello,world简单示例&#xff0c;VS下编写纯代码的界面&#xff1a; http://c.biancheng.net/view/1824.html 第一步&#xff1a; 第二…

(转) 基于MapReduce的ItemBase推荐算法的共现矩阵实现(一)

转自&#xff1a;http://zengzhaozheng.blog.51cto.com/8219051/1557054 一、概述 这2个月为公司数据挖掘系统做一些根据用户标签情况对用户的相似度进行评估&#xff0c;其中涉及一些推荐算法知识&#xff0c;在这段时间研究了一遍《推荐算法实践》和《Mahout in action》&…

Waymo十周年:多尔戈夫讲述从被嘲笑到硕果累累

来源&#xff1a;TechCrunch 编译&#xff1a;网易智能十年前&#xff0c;大约十几名工程师聚集在谷歌位于查尔斯顿路上的山景城&#xff0c;为"司机项目"献力&#xff0c;这是该科技巨头的“X工厂”旗下的一个秘密项目。这个司机项目俗称“谷歌自动驾驶汽车项目”&a…

中国AI登上Nature子刊:看病历分析儿科疾病,准确率90%,超人类医师

铜灵 发自 凹非寺量子位 出品 | 公众号 QbitAIAI大夫的能力又精进了。以前的AI要想要辅助人类诊断&#xff0c;得先学会输入大量带标注的医学影像训练模型。现在不用了&#xff0c;AI只需读一读电子文字简历&#xff0c;就能具备病情分析能力。有产品有真相。最近&#xff0c;A…