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;含义。

由于链表的交换会对切断节点的连接,因此要提前使用tmptmp1作为临时节点对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.环形链表Ⅱ的更多相关文章

  1. 【算法训练营day4】LeetCode24. 两两交换链表中的结点 LeetCode19. 删除链表的倒数第N个结点 LeetCode面试题 02.07. 链表相交 LeetCode142. 环形链表II

    [算法训练营day4]LeetCode24. 两两交换链表中的结点 LeetCode19. 删除链表的倒数第N个结点 LeetCode面试题 02.07. 链表相交 LeetCode142. 环形链表 ...

  2. 代码随想录训练营day 5|24.两两交换链表中的节点 19.删除链表的倒数第N个节点 面试题02.07.链表相交 142.环形链表Ⅱ

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

  3. 代码随想录算法训练营day04 | leetcode

    基础知识 记录一下栈实现及操作 public class ArrayDequeStack { public void main() { ArrayDeque stack = new ArrayDequ ...

  4. 代码随想录算法训练营day17 | leetcode ● 110.平衡二叉树 ● 257. 二叉树的所有路径 ● 404.左叶子之和

    LeetCode 110.平衡二叉树 分析1.0 求左子树高度和右子树高度,若高度差>1,则返回false,所以我递归了两遍 class Solution { public boolean is ...

  5. 代码随想录算法训练营day03 | LeetCode 203/707/206

    基础知识 数据结构初始化 // 链表节点定义 public class ListNode { // 结点的值 int val; // 下一个结点 ListNode next; // 节点的构造函数(无 ...

  6. 代码随想录算法训练营day01 | leetcode 704/27

    前言   考研结束半个月了,自己也简单休整了一波,估了一下分,应该能进复试,但还是感觉不够托底.不管怎样,要把代码能力和八股捡起来了,正好看到卡哥有这个算法训练营,遂果断参加,为机试和日后求职打下一个 ...

  7. 代码随想录算法训练营day21 | leetcode ● 530.二叉搜索树的最小绝对差 ● 501.二叉搜索树中的众数 ● ***236. 二叉树的最近公共祖先

    LeetCode 530.二叉搜索树的最小绝对差 分析1.0 二叉搜索树,中序遍历形成一个升序数组,节点差最小值一定在中序遍历两个相邻节点产生 ✡✡✡ 即 双指针思想在树遍历中的应用 class So ...

  8. 代码随想录算法训练营day18 | leetcode 513.找树左下角的值 ● 112. 路径总和 113.路径总和ii ● 106.从中序与后序遍历序列构造二叉树

    LeetCode 513.找树左下角的值 分析1.0 二叉树的 最底层 最左边 节点的值,层序遍历获取最后一层首个节点值,记录每一层的首个节点,当没有下一层时,返回这个节点 class Solutio ...

  9. 代码随想录算法训练营day14 | leetcode 层序遍历 226.翻转二叉树 101.对称二叉树 2

    层序遍历 /** * 二叉树的层序遍历 */ class QueueTraverse { /** * 存放一层一层的数据 */ public List<List<Integer>&g ...

  10. 代码随想录算法训练营day22 | leetcode 235. 二叉搜索树的最近公共祖先 ● 701.二叉搜索树中的插入操作 ● 450.删除二叉搜索树中的节点

    LeetCode 235. 二叉搜索树的最近公共祖先 分析1.0  二叉搜索树根节点元素值大小介于子树之间,所以只要找到第一个介于他俩之间的节点就行 class Solution { public T ...

随机推荐

  1. RTC 科普视频丨聊聊空间音频的原理与其背后的声学原理

    在现在很多的线上实时互动场景中,我们重视的不仅仅是互动体验,还要提升沉浸感.而在很多场景中,仅凭空间音频技术,就可以带来如临其境的体验.空间音频技术的原理是怎样的呢? 看过我们新一期的 RTC 科普视 ...

  2. Java:数据表的字段设计了默认值0不生效的原因

    在数据表里给字段设置了默认值为0,但是在插入的时候不生效,数据表设计如下 通过数据表生成的实体类 查看代码 @Data @TableName(value = "user") @No ...

  3. 玩转Mybatis高级特性:让你的数据操作更上一层楼

    目录 动态SQL 缓存机制 插件机制 自定义类型转换 总结 Mybatis高级特性能够帮助我们更加灵活地操作数据库,包括动态SQL.缓存机制.插件机制.自定义类型转换等.学习这些特性可以让我们更好地利 ...

  4. Laf v1.0 发布:函数计算只有两种,30s 放弃的和 30s 上线的

    一般情况下,开发一个系统都需要前端和后端,仅靠一个人几乎无法胜任,需要考虑的特性和功能非常多,比如: 需要一个数据库来存放数据: 需要一个文件存储来存放各种文件,比如图片文件: 后端需要提供接口供前端 ...

  5. vue中实用小技巧,长期更新

    1.在vue 中使用webpack require.context工程化配置组件,不用一个一个import注册了 main.js中 import Vue from 'vue'//使用lodsh插件im ...

  6. 深入理解 python 虚拟机:字节码灵魂——Code obejct

    深入理解 python 虚拟机:字节码灵魂--Code obejct 在本篇文章当中主要给大家深入介绍在 cpython 当中非常重要的一个数据结构 code object! 在上一篇文章 深入理解 ...

  7. 二进制安装Kubernetes(k8s) v1.25.0 IPv4/IPv6双栈

    二进制安装Kubernetes(k8s) v1.25.0 IPv4/IPv6双栈 Kubernetes 开源不易,帮忙点个star,谢谢了 介绍 kubernetes(k8s)二进制高可用安装部署,支 ...

  8. 四月十一号Java基础知识

    1.下列格式调用JAVA语言定义的方法:字符串变量名.方法名():2.由键盘输入多个数据普通格式一:Scanner reader= new Scanner(System.in): int number ...

  9. MordernC++之 auto 和 decltype

    在C++11标准中,auto作为关键字被引入,可以用来自动推导变量类型,auto可以用于定义变量,函数返回值,lambda表达式等,在定义变量时可以使用auto来代替具体类型,编译器根据变量初始化表达 ...

  10. wpf RelativeSource绑定

    RelativeSource有四种类型 Self FindAncestor TemplatedParent PreviousData a.Self Self用于绑定源和绑定目标相同的场景中.对象的一个 ...