# 代码随想录算法训练营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 ...
随机推荐
- 做bad apple第二步: python如何将视频变成一帧帧的图片,如何将一帧帧的图片转为视频
直接上代码 """视频转图片""" port cv2def getphoto(video_in, video_save): cap = cv ...
- 【NLP 系列】Bert 词向量的空间分布
作者:京东零售 彭馨 1. 背景 我们知道Bert 预训练模型针对分词.ner.文本分类等下游任务取得了很好的效果,但在语义相似度任务上,表现相较于 Word2Vec.Glove 等并没有明显的提升. ...
- 10 个杀手级的 Python 自动化脚本
重复性任务总是耗时且无聊,想一想你想要一张一张地裁剪 100 张照片或 Fetch API.纠正拼写和语法等工作,所有这些任务都很耗时,为什么不自动化它们呢?在今天的文章中,我将与你分享 10 个 P ...
- better-scroll横向滚动、纵向滚动
<div ref="tab" class="tab"> <ul ref="tabWrapper" class=" ...
- ABC291题解(D-G)
ABC291 D - Flip Cards Solution: 考虑DP,定义状态\(F_{i,0}\)为第\(i\)张卡片正面朝上的方案数,\(F_{i,1}\)为第\(i\)张卡片背面朝上的方案数 ...
- Let和Const区别,详细版本
let:声明的是变量1.不存在变量提升 // var 的情况 console.log(foo); // 输出undefined var foo = 2; // let 的情况 console.log( ...
- 如何快速在Ubuntu上搭建python环境?
如何快速在Ubuntu上搭建python环境? 一.准备好python源码包 使用curl命令获取python源码包的过程很缓慢且容易失败,因此提前去官网下载好后放在本地是最好的办法. 二.启动镜像并 ...
- 最新版本 Stable Diffusion 开源 AI 绘画工具之使用篇
目录 界面参数 采样器 文生图(txt2img) 图生图(img2img) 模型下载 界面参数 在使用 Stable Diffusion 开源 AI 绘画之前,需要了解一下绘画的界面和一些参数的意义 ...
- 在k8s安装CICD-devtron
在k8s安装CICD-devtron 先前条件 <kubernetes(k8s) 存储动态挂载>参考我之前的文档进行部署https://www.oiox.cn/index.php/arch ...
- [Linux]常用命令之【mkdir/touch/cp/rm/ls/mv】
cp 将来源文件夹packageA下的所有目录及文件复制到新文件夹packageB下,形成: /packageB/... # cp -r /home/packageA/* /home/cp/packa ...