# 代码随想录算法训练营Day4|24.两两交换链表中的节点 19.删除链表的倒数第N个节点 面试题02.07.链表相交 142.环形链表Ⅱ
24.两两交换链表中的节点
题目链接:24.两两交换链表中的节点
总体思路:
两两交换链表中的节点使用虚拟头节点可以更方便地进行交换,这样头节点和普通节点可以以同一种方式进行。
虚拟头结点的建设代码:
ListNode* dummyHead=new ListNode(0);
dummyHead->next=head;
交换思路:
- 步骤一:用虚拟头节点连接第二个节点,准备交换
- 步骤二:1、2两节点进行交换
- 步骤三:虚拟头节点向后移两位,准备进行下一组交换
cur->next=cur->next->next;//步骤1
cur->next->next=tmp;//步骤2
cur->next->next->next=tmp1;//步骤3
cur->next
既代表着指针域,也代表着下一个节点
、、
代码实现
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummyHead = new ListNode(0); // 设置一个虚拟头结点
dummyHead->next = head; // 将虚拟头结点指向head,这样方面后面做删除操作
ListNode* cur = dummyHead;
while(cur->next != nullptr && cur->next->next != nullptr) {
ListNode* tmp = cur->next; // 记录临时节点
ListNode* tmp1 = cur->next->next->next; // 记录临时节点
cur->next = cur->next->next; // 步骤一
cur->next->next = tmp; // 步骤二
cur->next->next->next = tmp1; // 步骤三
cur = cur->next->next; // cur移动两位,准备下一轮交换
}
return dummyHead->next;
}
};
bullptr
是C++中声明空指针的关键字,cur->next!=nullptr
表示current节点的下一个不是空指针,因为cur
是虚拟头指针,所以通过cur的移动进行,cur->next->next
等同于cur+=2;
含义。
由于链表的交换会对切断节点的连接,因此要提前使用tmp
、tmp1
作为临时节点对2、3号节点进行托管和存放。
19.删除链表的的倒数第N个节点
题目链接:19.删除链表的的倒数第N个节点
总体思路:
和数组中的移除元素相同,通过快慢指针进行,唯一需要改变的就是从链表最后的节点开始操作,到最开始倒向进行。
在删除节点时仍要考虑是否为头节点,因此设置为虚拟头节点会更方便。
链表的最后一个节点在于其tmp->next=nulltpr
。
使用虚拟头节点进行查找。
- 定义fast指针和slow指针,初始值为虚拟头节点
- fast首先走n+1步,这样保证slow在移动时可以指向删除结点的上一个节点,从而使删除更方便
- fast和slow同时移动,直到fast指向末尾
删除slow指向的下个节点
代码实现:
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummyHead = new ListNode(0);
dummyHead->next = head;
ListNode* slow = dummyHead;
ListNode* fast = dummyHead;
while(n-- && fast != NULL) {
fast = fast->next;
}
fast = fast->next; // fast再提前走一步,因为需要让slow指向删除节点的上一个节点
while (fast != NULL) {
fast = fast->next;
slow = slow->next;
}
slow->next = slow->next->next;
// ListNode *tmp = slow->next; C++释放内存的逻辑
// slow->next = tmp->next;
// delete nth;
return dummyHead->next;
}
};
面试题02.07. 链表相交
题目链接:面试题02.07.链表相交
总体思路:
两个链表相交,需注意,相交不是数值相等,是指针相等。
看如下两个链表,目前curA指向链表A的头结点,curB指向链表B的头结点:
我们求出两个链表的长度,并求出两个链表长度的差值,然后让curA移动到,和curB 末尾对齐的位置,如图:
此时我们就可以比较curA和curB是否相同,如果不相同,同时向后移动curA和curB,如果遇到curA == curB,则找到交点。
代码实现
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* curA=headA;
ListNode* curB=headB;
int LenA=0,LenB=0;
while(curA!=NULL){//求链表A的长度
lenA++;
curA=curA->next;
}
while(curB!=NULL){//求链表B的长度
lenB++;
curB=curB->next;
}
curA=headA;
curB=headB;
//让给curA为最长的链表,LenA为其长度
if(lenB>lenA){
swap(LenA,LenB);
swap(curA,curB);
}
//求长度差
int gap=LenA-LenB;
//让A和B在同一起点上(末尾位置对齐)
while(gap--){
curA=curA->next;
}
//遍历curA和curB遇到相同的则返回
while(curA!=NULL){
if(curB==curA){
return curA;
}
curA=curA-next;
curB=curb->next
}
return NULL;
}
};
否则循环退出返回空指针。
- 时间复杂度O(n+m)
- 空间复杂度O(1)
142.环形链表Ⅱ
题目链接:142.环形链表Ⅱ
总体思路
本题主要考察:
- 判断链表是否有环
- 如果有环,如何找到环的入口
判断链表是否有环
使用快慢指针,fastNode每次移动两个节点fastNode=fastNode->next->next
,slowNode每次移动一个节点slowNode=slowNode->next
,如果相遇if(fastNode==slowNode)
,则说明链表有环
如果有环,如何判断入口
假设从头结点到环形入口节点 的节点数为x。 环形入口节点到 fast指针与slow指针相遇节点 节点数为y。 从相遇节点 再到环形入口节点节点数为 z。 如图所示:
相遇时,slow指针走过x+y
,fast指针走过x+y+n(y+z)
,因为在圆内的相遇说明fast一定会比slow快一圈。
因为fast指针是一步走两个节点,slow指针一步走一个节点, 所以 fast指针走过的节点数 = slow指针走过的节点数 * 2:(x+y)*2=x+y+n(y+z)
=>x+y=n(y+z)
因为要求的是环的入口,所以即求x的数值,即x=z+(n-1)y
,从n(y+z)
提出(y+z)
有x=(n-1)(y+z)+z
注意,n一定大于1,因为这样fastNode才能比slowNode快一圈。
同时,fast是每次移动两个节点,,slow是每次移动一个节点,所以fast速度作为slow的两倍一定可以与slow相交。
代码实现
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* fastNode=head; //定义快节点
LostNode* slowNode=head; //定义慢节点
while(fastNode!=NULL&&fastNode->next!=NULL){
fastNode=fastNode->next->next; //快节点一次移动两个,因为要移动,所以要在while里移动
slowNode=slowNode->next; //慢节点一次移动一个节点
if(slowNode==fastNode){ //当快慢节点重合时
ListNode* index1=fastNode; //
ListNode* index2=slowNode;
while(index1!=index2){
index1=index1->next;//index
index2=index2->next;
}
return index2;
}
}
return NULL;
}
};
总结
- 链表的种类主要为:单链表,双链表,循环链表
- 链表的存储方式:链表的节点在内存中是分散存储的,通过指针连在一起。
- 链表是如何进行增删改查的。
- 数组和链表在不同场景下的性能分析。
链表的虚拟头节点
虚拟头节点的设置是增删改查中十分重要的方法,通过设置虚拟头节点,链表在进行操作时可以不用区分进行头节点和非头节点的操作,使更加方便
ListNode* dummyNode=new ListNode(0);
dummyNode->next=head;
链表的基本操作
这是练习链表基础操作的非常好的一道题目,考察了:
- 获取链表第index个节点的数值
- 在链表的最前面插入一个节点
- 在链表的最后面插入一个节点
- 在链表第index个节点前面插入一个节点
- 删除链表的第index个节点的数值
可以说把这道题目做了,链表基本操作就OK了,再也不用担心链表增删改查整不明白了。
反转链表
反转链表是十分高频的考点。先学透迭代法,然后再看递归法,因为递归法比较绕,如果迭代还写不明白,递归基本也写不明白了。
可以先通过迭代法,彻底弄清楚链表反转的过程!
# 代码随想录算法训练营Day4|24.两两交换链表中的节点 19.删除链表的倒数第N个节点 面试题02.07.链表相交 142.环形链表Ⅱ的更多相关文章
- 【算法训练营day4】LeetCode24. 两两交换链表中的结点 LeetCode19. 删除链表的倒数第N个结点 LeetCode面试题 02.07. 链表相交 LeetCode142. 环形链表II
[算法训练营day4]LeetCode24. 两两交换链表中的结点 LeetCode19. 删除链表的倒数第N个结点 LeetCode面试题 02.07. 链表相交 LeetCode142. 环形链表 ...
- 代码随想录训练营day 5|24.两两交换链表中的节点 19.删除链表的倒数第N个节点 面试题02.07.链表相交 142.环形链表Ⅱ
24. 两两交换链表中的节点 题目链接:24. 两两交换链表中的节点 题目描述:给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点.你必须在不修改节点内部的值的情况下完成本题(即,只能进行 ...
- 代码随想录算法训练营day04 | leetcode
基础知识 记录一下栈实现及操作 public class ArrayDequeStack { public void main() { ArrayDeque stack = new ArrayDequ ...
- 代码随想录算法训练营day17 | leetcode ● 110.平衡二叉树 ● 257. 二叉树的所有路径 ● 404.左叶子之和
LeetCode 110.平衡二叉树 分析1.0 求左子树高度和右子树高度,若高度差>1,则返回false,所以我递归了两遍 class Solution { public boolean is ...
- 代码随想录算法训练营day03 | LeetCode 203/707/206
基础知识 数据结构初始化 // 链表节点定义 public class ListNode { // 结点的值 int val; // 下一个结点 ListNode next; // 节点的构造函数(无 ...
- 代码随想录算法训练营day01 | leetcode 704/27
前言 考研结束半个月了,自己也简单休整了一波,估了一下分,应该能进复试,但还是感觉不够托底.不管怎样,要把代码能力和八股捡起来了,正好看到卡哥有这个算法训练营,遂果断参加,为机试和日后求职打下一个 ...
- 代码随想录算法训练营day21 | leetcode ● 530.二叉搜索树的最小绝对差 ● 501.二叉搜索树中的众数 ● ***236. 二叉树的最近公共祖先
LeetCode 530.二叉搜索树的最小绝对差 分析1.0 二叉搜索树,中序遍历形成一个升序数组,节点差最小值一定在中序遍历两个相邻节点产生 ✡✡✡ 即 双指针思想在树遍历中的应用 class So ...
- 代码随想录算法训练营day18 | leetcode 513.找树左下角的值 ● 112. 路径总和 113.路径总和ii ● 106.从中序与后序遍历序列构造二叉树
LeetCode 513.找树左下角的值 分析1.0 二叉树的 最底层 最左边 节点的值,层序遍历获取最后一层首个节点值,记录每一层的首个节点,当没有下一层时,返回这个节点 class Solutio ...
- 代码随想录算法训练营day14 | leetcode 层序遍历 226.翻转二叉树 101.对称二叉树 2
层序遍历 /** * 二叉树的层序遍历 */ class QueueTraverse { /** * 存放一层一层的数据 */ public List<List<Integer>&g ...
- 代码随想录算法训练营day22 | leetcode 235. 二叉搜索树的最近公共祖先 ● 701.二叉搜索树中的插入操作 ● 450.删除二叉搜索树中的节点
LeetCode 235. 二叉搜索树的最近公共祖先 分析1.0 二叉搜索树根节点元素值大小介于子树之间,所以只要找到第一个介于他俩之间的节点就行 class Solution { public T ...
随机推荐
- C#MD5加密的两种方式
在开发过程当中,我们经常会用到MD5加密,下面介绍MD5加密的两种方式: /// <summary> /// MD5字符串加密 /// </summary> /// <p ...
- Windows7卡在正在关机
据我的分析,Windows系统卡在正在关机的原因很大可能性是破解过系统主题.解决方法就是还原成主题未被破解时候的状态.但是这种情况是随机性的,但是可以确定的是,只要是破解过系统主题,都有一定概率关不了 ...
- es6数组相关操作
1. 获取两个数组中某个属性值相等的项 let a=[{name:1},{name:4},{name:3}] let b=[{name:5},{name:4},{name:2}] let index ...
- 关于在vue3中使用vuex与在vue2中使用vuex的区别
首先vue2中vuex版本是4.x以下,vue3中使用vuex需要保证vuex版本在4.x及以上. 以下说一说怎么在vue3中使用vuex,与vue2大同小异 首先在views新建一个store文件夹 ...
- kubernetes核心实战(三)--- ReplicationController
5.ReplicationController ReplicationController 确保在任何时候都有特定数量的 Pod 副本处于运行状态.换句话说,ReplicationController ...
- w32模块模拟鼠标键盘操作
win32api.keybd_event 该函数原型:keybd_event(bVk, bScan, dwFlags, dwExtraInfo) 第一个参数:虚拟键码(键盘键码对照表见附录): 第二个 ...
- [PKM]阅读的方法
0 概述 数据 => 信息 => 知识 => 智慧 1 读书的目的 : 先寻求真理,而后实践 => 先博学,而后守约(读透) & 先泛读/速读,再精读 / 知行合一 年 ...
- [Linux]常用命令之【history】#查看历史操作#
1 历史记录: history history命令就是历史记录. 它显示了在终端中所执行过的所有命令的历史. history //显示终端执行过的命令 history 10 //显示最近10条终端执行 ...
- MQTT(EMQX) - SpringBoot 整合MQTT 连接池 Demo - 附源代码 + 在线客服聊天架构图
MQTT(EMQX) - Linux CentOS Docker 安装 MQTT 概述 MQTT (Message Queue Telemetry Transport) 是一个轻量级传输协议,它被设计 ...
- linux CentOS 7上安装Chrome浏览器
目录 linux CentOS 7上安装Chrome浏览器 添加Chrome浏览器的官方存储库,使用以下命令: 安装Chrome浏览器: 确认Chrome浏览器是否安装成功: linux CentOS ...