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

    用虚拟头结点,这样会方便很多。

    本题链表操作就比较复杂了,建议大家先看视频,视频里我讲解了注意事项,为什么需要temp保存临时节点。

    题目链接/文章讲解/视频讲解: https://programmercarl.com/0024.两两交换链表中的节点.html

题目感想:

1.面对链表的题目为了方便处理,定义一个虚拟头节点,大概的思路就是,先让指针指向当前节点的NEXT节点,先保存NEXT节点的原始NEXT节点,然后使得NEXT节点的NEXT为它的前置节点,这样1、2节点的位置就替换过来了,然后cur指针再指向刚刚保存的那个节点,开始下一步操作;

 public ListNode swapPairs(ListNode head) {
ListNode dumyhead = new ListNode(-1); // 设置一个虚拟头结点
dumyhead.next = head; // 将虚拟头结点指向head,这样方便后面做删除操作
ListNode cur = dumyhead;
ListNode temp; // 临时节点,保存两个节点后面的节点
ListNode firstnode; // 临时节点,保存两个节点之中的第一个节点
ListNode secondnode; // 临时节点,保存两个节点之中的第二个节点
while (cur.next != null && cur.next.next != null) {
temp = cur.next.next.next;
firstnode = cur.next;
secondnode = cur.next.next;
cur.next = secondnode; // 步骤一
secondnode.next = firstnode; // 步骤二
firstnode.next = temp; // 步骤三
cur = firstnode; // cur移动,准备下一轮交换
}
return dumyhead.next;
} // 将步骤 2,3 交换顺序,这样不用定义 temp 节点
public ListNode swapPairs(ListNode head) {
ListNode dummy = new ListNode(0, head);
ListNode cur = dummy;
while (cur.next != null && cur.next.next != null) {
ListNode node1 = cur.next;// 第 1 个节点
ListNode node2 = cur.next.next;// 第 2 个节点
cur.next = node2; // 步骤 1
node1.next = node2.next;// 步骤 3
node2.next = node1;// 步骤 2
cur = cur.next.next;
}
return dummy.next;
}

2.还有一种方法是使用递归,先通过递归抵达链表末尾,递归回去的时候,就进行交换

    public ListNode swapPairs(ListNode head) {
// base case 退出提交
if(head == null || head.next == null) return head;
// 获取当前节点的下一个节点
ListNode next = head.next;
// 进行递归
ListNode newNode = swapPairs(next.next);
// 这里进行交换
next.next = head;
head.next = newNode; return next;
}

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

双指针的操作,要注意,删除第N个节点,那么我们当前遍历的指针一定要指向 第N个节点的前一个节点,建议先看视频。

题目链接/文章讲解/视频讲解:https://programmercarl.com/0019.删除链表的倒数第N个节点.html

题目感想:

1.这里也定义虚拟头节点,然后通过快慢指针,因为要删除倒数的第N个节点,也就是距离尾部的距离为N的节点,所以我们先定义两个指针,快指针要先于慢指针走N个节点,然后两个节点再一起走,直到快指针抵达链表末尾;

2.需要注意定义了虚拟头节点的影响,以及快指针和慢指针之间的距离,慢指针停留下来要在想要删除节点的前面,这样才能便于删除操作;

 public ListNode removeNthFromEnd(ListNode head, int n) {
//新建一个虚拟头节点指向head
ListNode dummyNode = new ListNode(0);
dummyNode.next = head;
//快慢指针指向虚拟头节点
ListNode fastIndex = dummyNode;
ListNode slowIndex = dummyNode; // 只要快慢指针相差 n 个结点即可
for (int i = 0; i <= n; i++) {
fastIndex = fastIndex.next;
}
while (fastIndex != null) {
fastIndex = fastIndex.next;
slowIndex = slowIndex.next;
} // 此时 slowIndex 的位置就是待删除元素的前一个位置。
// 具体情况可自己画一个链表长度为 3 的图来模拟代码来理解
// 检查 slowIndex.next 是否为 null,以避免空指针异常
if (slowIndex.next != null) {
slowIndex.next = slowIndex.next.next;
}
return dummyNode.next;
}

面试题 02.07. 链表相交

本题没有视频讲解,大家注意 数值相同,不代表指针相同。

题目链接/文章讲解:https://programmercarl.com/面试题02.07.链表相交.html

题目感想:

1.这题链表相交是不含环的,且链表相交后的节点都一致,基于这个我们才能解题;

2.第一种方法就是因为相交后的节点都一样,所以我们先判断两个链表的长度,然后将两个链表的尾部对齐,也就是定义了两个指针在两个链表尾部对齐的前提下进行遍历,如果两个指针的值一样就说明找到交点了;

(版本一)先行移动长链表实现同步移动
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) {
//1. swap (lenA, lenB);
int tmpLen = lenA;
lenA = lenB;
lenB = tmpLen;
//2. swap (curA, curB);
ListNode tmpNode = curA;
curA = curB;
curB = tmpNode;
}
// 求长度差
int gap = lenA - lenB;
// 让curA和curB在同一起点上(末尾位置对齐)
while (gap-- > 0) {
curA = curA.next;
}
// 遍历curA 和 curB,遇到相同则直接返回
while (curA != null) {
if (curA == curB) {
return curA;
}
curA = curA.next;
curB = curB.next;
}
return null;
} }

3.第二种方法就是定义两个指针分别开始遍历两个链表,遍历完本链表就去遍历另外一条链表,如果遍历期间有相同的指针就是入口了。

这个原因是假设两个链表相交,那么他们的相同部分是c,不同部分分别是a,b,那么按照上述遍历,将会走同样长的路程就能得到入口点了;

(版本二) 合并链表实现同步移动
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
// p1 指向 A 链表头结点,p2 指向 B 链表头结点
ListNode p1 = headA, p2 = headB;
while (p1 != p2) {
// p1 走一步,如果走到 A 链表末尾,转到 B 链表
if (p1 == null) p1 = headB;
else p1 = p1.next;
// p2 走一步,如果走到 B 链表末尾,转到 A 链表
if (p2 == null) p2 = headA;
else p2 = p2.next;
}
return p1;
}
}

142.环形链表II

算是链表比较有难度的题目,需要多花点时间理解 确定环和找环入口,建议先看视频。

题目链接/文章讲解/视频讲解:https://programmercarl.com/0142.环形链表II.html

题目感想:

1.首先我们要确定是否有环,可以定义两个快慢指针,快指针一下走两个,慢指针一下走一个,如果有环的话他们一定会相交,没有环的就会遍历到链表末尾;

2.有环就需要找到环的入口,这个推到过程可以去看上面的链接里面,详细介绍了为什么会在慢指针走在环中的第一圈相遇,以及为什么定义两个指针,一个从相遇节点出发,一个从起始节点出发,每次走一格,最终相遇的地方是环的入口;

 public ListNode detectCycle(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {// 有环
ListNode index1 = fast;
ListNode index2 = head;
// 两个指针,从头结点和相遇结点,各走一步,直到相遇,相遇点即为环入口
while (index1 != index2) {
index1 = index1.next;
index2 = index2.next;
}
return index1;
}
}
return null;
}

代码随想录第四天 | 链表part02的更多相关文章

  1. 代码随想录第四天| 24. 两两交换链表中的节点 、19.删除链表的倒数第N个节点 、160.链表相交、142.环形链表II

    今天链表致死量 第一题 public static class ListNode { int val; ListNode next; ListNode() {} ListNode(int val) { ...

  2. 代码随想录训练营day 4|链表基础理论,移除链表元素,设计链表,反转链表

    链表理论基础 链表是一种由指针串联在一起的线性结构,每一个节点都由一个数据域和一个指针域组成. 链表的类型有:单链表.双链表.循环链表. 链表的存储方式:在内存中不连续分布. 链表的定义很多人因为不重 ...

  3. 代码随想录第八天 |344.反转字符串 、541. 反转字符串II、剑指Offer 05.替换空格 、151.翻转字符串里的单词 、剑指Offer58-II.左旋转字符串

    第一题344.反转字符串 编写一个函数,其作用是将输入的字符串反转过来.输入字符串以字符数组 s 的形式给出. 不要给另外的数组分配额外的空间,你必须原地修改输入数组.使用 O(1) 的额外空间解决这 ...

  4. 代码随想录-day1

    链表 今天主要是把链表专题刷完了,链表专题的题目不是很难,基本都是考察对链表的操作的理解. 在处理链表问题的时候,我们通常会引入一个哨兵节点(dummy),dummy节点指向原链表的头结点.这样,当我 ...

  5. C代码实现非循环单链表

    C代码实现非循环单链表, 直接上代码. # include <stdio.h> # include <stdlib.h> # include <malloc.h> ...

  6. .net之工作流工程展示及代码分享(四)主控制类

    现在应该讲主控制类了,为了不把系统弄得太复杂,所以就用一个类作为主要控制类(服务类),作为前端.后端.业务逻辑的控制类. WorkflowService类的类图如下: 该类的构造函数: public ...

  7. Python实现C代码统计工具(四)

    目录 Python实现C代码统计工具(四) 标签: Python 计时 持久化 声明 运行测试环境 一. 自定义计时函数 1.1 整个程序计时 1.2 代码片段计时 1.3 单条语句计时 二. 性能优 ...

  8. 微信小游戏 demo 飞机大战 代码分析(四)(enemy.js, bullet.js, index.js)

    微信小游戏 demo 飞机大战 代码分析(四)(enemy.js, bullet.js, index.js) 微信小游戏 demo 飞机大战 代码分析(一)(main.js) 微信小游戏 demo 飞 ...

  9. WebShell代码分析溯源(四)

    WebShell代码分析溯源(四) 一.一句话变形马样本 <?php @$_++;$__=("`"^"?").(":"^"} ...

  10. 恶意代码分析实战四:IDA Pro神器的使用

    目录 恶意代码分析实战四:IDA Pro神器的使用 实验: 题目1:利用IDA Pro分析dll的入口点并显示地址 空格切换文本视图: 带地址显示图形界面 题目2:IDA Pro导入表窗口 题目3:交 ...

随机推荐

  1. CTF-CRYPTO-ECC(1)

    CTF-CRYPTO-ECC(1) 椭圆加密 1.简介 椭圆曲线密码学(Elliptic curve cryptography),简称 ECC,和RSA.ElGamel 算法等类似,是一种公开秘钥加密 ...

  2. 对称&反对称&完全固定边界条件

    ABAQUS Boundary Condition XSYMM 对称边界条件,对称面为与坐标轴1垂直的平面,即U1=UR2=UR3=0; YSYMM 对称边界条件,对称面为与坐标轴2垂直的平面,即U2 ...

  3. Vulnhub-Source-1(CVE-2019-15107)

    一.靶机搭建 选择打开选项 选中下载的ova文件,然后导入选择一个存放路径即可 如果遇到不兼容的情况,可以打开.vmx修改,改为和虚拟机一个版本号 二.信息收集 官方信息 Name: Source: ...

  4. jQuery ajax 文件上传 Request Headers 缺少 boundary

    原文地址: https://blog.jijian.link/2020-07-28/jquery-ajax-upload-file/ 一般上传方式 const file = document.getE ...

  5. 地图可视化,根据绘制的图形生成缩略图,经纬度转换二维canvas坐标系

    一.h5在做可视化地图时,用高德地图绘制空域(圆形,线,多边形),碰到一个需求,根据绘制出来的图形给对应的空域列表项添加一个缩略图. 二.确定实现方法 要根据绘制的图形生成对应图形的缩略图,有两种方式 ...

  6. linux生成ssh密钥

    前言 我们一般使用 PuTTY 等 SSH 客户端来远程管理 Linux 服务器.但是,一般的密码方式登录,容易有密码被暴力破解的问题.所以,一般我们会将 SSH 的端口设置为默认的 22 以外的端口 ...

  7. 一文搞懂MCP协议与Function Call的区别

    一.前言 大家好,我是六哥! 今天咱们聊聊编程里两个听起来有点复杂的概念--MCP协议和函数调用(function call),其实用大白话来讲,它们就是两种不同的"沟通方式",就 ...

  8. [每日算法 - 华为机试] leetcode690. 员工的重要性

    入口 力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台备战技术面试?力扣提供海量技术面试资源,帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer.https://le ...

  9. ro在xe10.3上的安装

    在学习研究RO. RO9.2.101.1295在xe10.3上安装遇到新问题.记录处理的办法: 没有采用执行exe安装的方法.而是采用复制源代码后编译安装. 1.把生成的bpl.dcp安装到默认目录, ...

  10. Jenkins pipeline之声明式的jenkinsfile

    Jenkins pipeline之声明式的jenkinsfile 内置的关键字 pipeline : 是pipeline的跟节点 agent: 定义piple使用哪个账号在哪个机器上执行 post: ...