代码随想录算法训练营第四天 | 24. 两两交换链表中的节点 19.删除链表的倒数第N个节点 面试题 02.07. 链表相交 142.环形链表II
创始人
2024-04-22 22:03:06

今天是链表章节最后一天,加油💪

24. 两两交换链表中的节点

题目:给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

示例 1:
输入:head = [1,2,3,4]
输出:[2,1,4,3]

示例 2:
输入:head = []
输出:[]

示例 3:
输入:head = [1]
输出:[1]


思路:本题需要借助几个临时节点完成交换,想要两辆交换节点,必须有临时节点保存第三个节点。假设前三个节点A、B、C,要交换AB节点的位置,需要新建一个虚拟头节点,并用指针curr指向虚拟头节点,用临时节点temp记录节点A,临时节点1temp1记录节点C,交换代码就是curr->next = curr->next->next; curr->next->next = temp; curr->next->next->next = temp1;也就是head->next = B; B->next = A; A->next = C;(交换代码的含义,不能直接用这个,注意链表节点交换时,要提前保存next指针指向的下一个节点,不然容易丢失下一个节点)

C++版本

class Solution {
public:ListNode* swapPairs(ListNode* head) {ListNode *head_ = new ListNode(0, head);ListNode *curr = head_;while (curr->next != 0 && curr->next->next != 0) { // 顺序不能颠倒,不然会出现空指针异常ListNode *temp = curr->next;ListNode *temp1 = curr->next->next->next;// 主要交换代码curr->next = curr->next->next;curr->next->next = temp;curr->next->next->next = temp1;curr = curr->next->next;}return head_->next;}
};

这题不算难,就是要注意一些细节的问题。


19.删除链表的倒数第N个节点

题目:给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

示例 1:
输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]

示例 2:
输入:head = [1], n = 1
输出:[]

示例 3:
输入:head = [1,2], n = 1
输出:[1]


思路:注意是删除倒数第n个节点,不要看错题目要求了!这题我写了两种方法,一种是直接法,首先遍历一遍链表算出链表长度以及倒数第n个节点属于正数第几个节点,然后再遍历一次找到要删除的节点的前一个节点,最后进行删除操作;另一种是利用快慢指针,双指针的方法实在是太妙了,令快慢指针都指向虚拟头节点,快指针先走n步,然后快慢指针再同时往前走,当快指针走到链表的最后一个节点时,慢指针正好在倒数第n+1个节点,便可进行删除操作。

C++版直接方法

class Solution {
public:ListNode* removeNthFromEnd(ListNode* head, int n) {  //删除倒数第n个ListNode *head_ = new ListNode(0, head);  // 创建一个虚拟头节点ListNode *curr = head_;ListNode *temp = head_;int l = 0; int t;  // while (temp != NULL) {  // 计算链表长度(从1开始)temp = temp->next;l++;t = l - n;  // 计算循环次数}while (--t) {curr = curr->next;  // 遍历到需要删掉的节点的上一个节点}curr->next = curr->next->next;return head_->next;}
};

C++版双指针

class Solution {
public:ListNode* removeNthFromEnd(ListNode* head, int n) {ListNode *head_ = new ListNode(0, head);ListNode *fast = head_;ListNode *slow = head_;while (n-- && fast != NULL) {fast = fast->next;  // fast先走n步}while (fast->next != NULL) {fast = fast->next;  // 当fast走到最后一个节点时slow = slow->next;  // slow走到倒数第n个节点的前一个节点?}slow->next = slow->next->next;return head_->next;}
};

一定要掌握双指针方法的核心思想,并学会灵活应用!太好用了!


面试题 02.07. 链表相交

题目:给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。
图示两个链表在节点 c1 开始相交:

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构 。

示例 1:

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Intersected at ‘8’

解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。
在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。


思路:注意不是数值相等算相交,是节点一样才算相交,这题我一开始没有什么思路,看了Carl哥的视频茅塞顿开!首先要明确,从相交的节点开始,后面的节点都是一样的,直到结束。这可不是一句废话,这是解题的关键。所以将两个链表末尾对齐,从后半部分找重合的节点即可。

C++版本

class Solution {
public:ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {ListNode *head_A = new ListNode(0, headA);ListNode *head_B = new ListNode(0, headB);ListNode *curr_A = head_A;ListNode *curr_B = head_B;int len_A = 0; int len_B = 0;while (curr_A->next != 0) {  // 计算链表A的长度len_A++;curr_A = curr_A->next;}while (curr_B->next != 0) {  // 计算链表B的长度len_B++;curr_B = curr_B->next;}curr_A = head_A;curr_B = head_B;if (len_B > len_A) {  // 保证最长的是链表Aswap (curr_A, curr_B);swap (len_A, len_B);}int t = len_A - len_B;  // 将两链表末尾对齐,curr_A需要移动的次数while (t--) {curr_A = curr_A->next;}while (curr_A !=NULL) {if (curr_A == curr_B) {return curr_A;  // 一个一个的返回重合的节点}curr_A = curr_A->next;curr_B = curr_B->next;}return NULL;}
};

这里的一个小tips是,将长链表放在curr_A,将短链表放在curr_B,方便了后续的操作。


142.环形链表II

题目:给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改 链表
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:
输入:head = [1,2], pos = 0
输出:返回索引为 0 的链表节点
解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:
输入:head = [1], pos = -1
输出:返回 null
解释:链表中没有环。


思路:不得不感叹双指针是真好用。本题需要一定的数学证明,详情请见代码随想录。本题第一步判断是否有环,第二步找环的入口。第一步:快指针一次走两步,慢指针一次走一步,当两指针相遇说明一定有环。第二步:令快指针起点为相遇点,慢指针起点为头节点,两指针每次都只走一步,下次相遇一定是在环的入口。具体证明见上述链接。

C++版本

class Solution {
public:ListNode *detectCycle(ListNode *head) {ListNode *fast = head;ListNode *slow = head;while (fast != 0 && fast->next != 0) {  // 快指针走两步,慢指针走一步fast = fast->next->next;slow = slow->next;if (fast == slow) {  // 快慢指针相遇,不能直接break,不然无法判断无环的情况ListNode *index_f = fast;  // 重新赋值index_f指针指向相遇点ListNode *index_h = head;  // 另一个index_h指针指向头节点while (index_f != index_h) {  // 再次相遇的点就是环的入口index_f = index_f->next;index_h = index_h->next;}return index_f;}} return NULL;  // 遍历结束快慢指针都没有相遇过,就没有环}
};

其实本题也可以采用 19.删除链表的倒数第N个节点 类似的思路,在找到相遇点后,让快指针绕环走一圈,计算出环的长度L;再将快慢指针重新指向头节点,这次让快指针先走L步,慢指针再和快指针一起移动,每次移动一步;因为快指针比慢指针多走了一个环的距离,所以下一次相遇一定是在环的入口!

这是训练营小伙伴 芒果冰冰 的解法,大家都很棒!像大家学习,加油💪

相关内容

热门资讯

长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
tag是什么意思 tab是什么... 一、B端基础控件的认识控件一词,直译的话可以翻译成 “用来控制的元件”,是我们对 B 端系统进行信息...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
tag是什么意思 tab是什么... 一、B端基础控件的认识控件一词,直译的话可以翻译成 “用来控制的元件”,是我们对 B 端系统进行信息...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...