代码随想录算法训练营第四天 | 链表 + 每日一题

简介: 代码随想录算法训练营第四天 | 链表 + 每日一题

一、前言

今天是算法的第四天,对链表阶段进行一个结尾,今日任务:

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

题目描述

网络异常,图片无法展示
|

思路分析

这道题我是使用了虚拟头节点方法来做的

内部实际就是循环遍历节点,然后提取不变的节点,两两交换节点,在赋值回去不变的节点就可以了

代码展示

public ListNode swapPairs(ListNode head) {
        // 设置虚拟头节点
        ListNode dummyNode = new ListNode(0);
        dummyNode.next = head;
        ListNode prev = dummyNode;
        // 先进行下一个节点的判断, 在进行下下个节点的判断, 避免空指针异常
        while (prev.next != null && prev.next.next != null) {
            // 缓存不变的链表信息(只动两个节点进行位置交换, 将两个节点之后的节点缓存下来)
            ListNode temp = prev.next.next.next;
            // 缓存第一个节点信息(先将第二个节点的位置放到第一个节点的位置上, 第一个节点就没有了节点信息)
            ListNode temp1 = prev.next;
            // 将第二个节点提取到第一个节点的位置
            prev.next = prev.next.next;
            // 将不变的链表放置到 原第一个节点后面
            temp1.next = temp;
            // 将原第一个节点放置到现第二个节点的位置
            prev.next.next = temp1;
            // 链表移动两位
            prev = prev.next.next;
        }
        return dummyNode.next;
    }
复制代码

提交结果

网络异常,图片无法展示
|

总结

这道题一个月之前做过,所以印象还是很深刻的,本题还可以通过递归来做,感兴趣的可以去看代码随想录网站

三、 19. 删除链表的倒数第 N 个结点

题目描述

网络异常,图片无法展示
|

思路分析

这道题还是通过虚拟头结点来做

难点在于我们不知道当前节点的长度,所以需要使用两个节点来做

先设置虚拟头结点 dummy,再用两个节点 = dummy,循环使 fast = fast.next, 循环结束之后 head长度 = n + fast长度,依此条件来对 slow进行循环获取到需要删除的节点

代码展示部分为上一次提交代码,注释更详细,本次提交代码可看【提交结果】

代码展示

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
   // 为了方便对头节点操作, 还是使用虚拟头节点 `dummy` 来做
    ListNode dummy = new ListNode(-1);
    dummy.next = head;
    // 创建一个链表 `slow` 表示当前节点
    ListNode slow = dummy;
    // 使用一个链表 `fast` 去获取当前节点后第n个节点
    ListNode fast = dummy;
    // 根据提示可知 n < 链表长度的, 所以使用fast去判断slow节点是不是倒数第n个节点
    while (n-- > 0) {
        fast = fast.next;
    }
    // 记住 待删除节点slow 的上一节点
    ListNode prev = null;
    // 循环终止条件是 `fast` 链表的 next == null
    while (fast != null) {
        // prev 存储当前节点
        prev = slow;
        // slow和fast节点向下进一步
        slow = slow.next;
        fast = fast.next;
    }
    // 循环结束之后, 上一节点是 prev, 下一节点是 slow.next, 删除show节点
    prev.next = slow.next;
    // 下面是看大佬代码的收获
    // 释放 待删除节点slow 的next指针, 这句删掉也能AC
    slow.next = null;
    return dummy.next;
    }
}
复制代码

提交结果

网络异常,图片无法展示
|

总结

这道题第一眼就被倒数节点蒙住了,还在想怎么解决,看了眼LeetCode上次提交的代码(咱就说不是故意的,进入页面之后编辑器上就有上次提交的代码展示),直接就会了,还是要做过啊,做过最少就有一些思路了

四、 面试题 02.07. 链表相交

题目描述

网络异常,图片无法展示
|

网络异常,图片无法展示
|

思路分析

咱就说, 以前做 LeetCode注释记录的真全面

这道题印象还是很深刻的,需要注意的一点是判断的是节点地址是否相同,而不是节点是否相同

根据示例可以知道,判断的关键在于两条链表的交点,那这个交点之后的链表长度肯定是相等的

  • 首选去获取两条链表的长度
  • 根据长度去对链表进行操作,使得两条链表长度保持一致
  • 在去遍历链表,去判断两个链表的节点是否相同,节点相同的话就直接返回,不同的话返回null

代码展示

public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        // 两个链表, 接受 headA和 headB
        ListNode nodeA = headA;
        ListNode nodeB = headB;
        // 记录两个链表的长度
        Integer skipA = 0, skipB = 0;
        // 计算出两个链表的长度
        while(nodeA != null){
            skipA++;
            nodeA = nodeA.next;
        }
        while(nodeB != null){
            skipB++;
            nodeB = nodeB.next;
        }
        // 循环结束之后要重新为两个链表赋值
        nodeA = headA;
        nodeB = headB;
        // 两个链表长度差
        Integer n = skipA - skipB;
        // 让链表A为最长链表, 方便我们后续移动链表操作
        if (skipA < skipB){
            // 交换链表节点
            ListNode node = nodeA;
            nodeA = nodeB;
            nodeB = node;
            // 如果B链表长. 那么长度差是负值, 所以这里要重新进行计算
            n = skipB - skipA;
        }
        // n是长度差, 缩短链表A至长度与B相等
        while(n-- > 0 ){
            nodeA = nodeA.next;
        }
        // 记录返回值
        ListNode node = null;
        // 循环判断链表值是否相等
        while(nodeA != null){
            // 如果两个值相等, 则跳出循环
            if (nodeA == nodeB){
                return nodeA;
            }
            nodeA = nodeA.next;
            nodeB = nodeB.next;
        }
        return null;
    }
复制代码

提交结果

网络异常,图片无法展示
|

总结

只能说,游刃有余,哈哈哈哈

五、 142. 环形链表 II

题目描述

网络异常,图片无法展示
|

解题思路

  • 首先,我们要去判断当前链表 head是不是环形链表
  • 新建两个链表 nodeA和 nodeB,去接收原链表 head
  • 循环遍历,nodeA每次前进一步,nodeB每次前进两步
  • 当链表相遇时,证明链表 head是环形链表
  • 如果不是环形链表,则直接返回 null
  • 如果是环形链表,那么 nodeA肯定会与 nodeB相遇
  • 因为 nodeA每次前进一步,nodeB每次前进两步,所以 nodeA绕环形链表部分走一圈时,nodeB会绕环形链表走两圈,这期间不论环形链表部分是单数链表还是双数链表,肯定会相遇最少一次
  • 现在我们确定了链表 head是环形链表之后,该去判断环形链表部分的初始节点位置,下面简称为入环点
  • 假设链表 head的头结点到入环点的距离为 x,入环点到相遇点为 y,相遇点到入环点为 z
  • 那么 nodeA走到相遇点的距离为 x + y
  • nodeB走到相遇点的距离为 n(y + z) + x + y
  • 又因为 nodeA走一步,nodeB走两步,所以: (x + y)* 2 = n(y + z) + x + y
  • 解得: x = n(y + z) -y
  • 整理可得: x = (n - 1)(y + z) + z
  • 因为 nodeA跑一步 nodeB跑两步,所以 n是肯定大于 1的
  • 又因为环形链表部分的长度等于 y + z
  • 所以 x = z + nodeA绕环形链表圈数
  • 那么我们现在要做的,就是让 nodeA跑 x距离,让 nodeB跑 (z + n圈)
  • 所以我们让 nodeA = head,让 nodeA从头开始跑
  • nodeB不变,因为当前 nodeB距离入环点就是 z的距离
  • 同时让 nodeA和 nodeB每次循环前进一位,保证两个节点肯定会在入环点相遇
  • 具体代码如下所示

代码展示

public static ListNode detectCycle(ListNode head) {
    // 搞两个链表,接收 head
    // A是慢链表,B是快链表
    ListNode nodeA = head;
    ListNode nodeB = head;
    // 判断该链表是否为环形链表
    boolean flag = false;
    while(nodeB != null && nodeB.next != null){
        nodeA = nodeA.next;
        nodeB = nodeB.next.next;
        if (nodeA == nodeB){
            flag = true;
            break;
        }
    }
    // 如果为环形链表,判断入口位置
    if (flag){
        nodeA = head;
        while(nodeA != nodeB){
            nodeA = nodeA.next;
            nodeB = nodeB.next;
        }
        return nodeA;
    }
    return null;
}
复制代码

提交结果

网络异常,图片无法展示
|

总结

这次解题思路和代码不是扒的上一次的了,是直接扒的之前的文章,本次完成代码在【提交结果】中

还记得我是从本题开始看的卡哥视频讲解,之后直接一发入魂

六、 1652. 拆炸弹

题目描述

网络异常,图片无法展示
|

思路分析

这道题我有三种思路去做

拼接数组

搞一个长度为 code.length * 2 的数组, 然后根据 k > 0或者小于 0的情况从后或者从前去遍历想加就可以了,很简单,但是很明显内存消耗会比较大

双重 for循环

for循环遍历 code数组,在根据 k > 0为判断条件写一个 for循环进行双重 for循环进行遍历,但是这个时间消耗也会很大,具体可能是 n * k倍?我不太会算这个,有大佬的话可以评论区指出来我会进行改正的

滑动窗口

先求出 code[0]位置上计算后的 sum,同时求出计算 code[0]处值范围的头 head下标和尾 tail下标,在遍历过程中,sum += code[head] - code[tail] 就可以了

我也是使用的这种方法做的

代码展示

public static int[] decrypt(int[] code, int k) {
    // 取出当前数组的长度
    int length = code.length;
    // 设置返回值
    int[] ans = new int[length];
    // 如果 k==0 则直接返回, int数组默认元素为 0
    if (k == 0){
        return ans;
    }
    // 初始化总和为 sum = 0, count代表首次计算总和时计算元素的个数,Math.abs()方法是求取绝对值的
    // 以 k>0 为条件,使用三元运算符动态获取头尾下标
    int sum = 0, count = Math.abs(k), tail = k > 0? 1: 0, head = k > 0? 0 : length-1;
    // 计算 ans[0] 的值
    while(count-- > 0){
        sum += k > 0? code[head = (head + 1) % length] : code[tail = (tail - 1 + length) % length];
    }
    // 赋值
    ans[0] = sum;
    // 循环为 ans数组进行赋值
    for (int i = 1; i < length; i++) {
        // 计算当前下标的 sum值, 同时 head++
        sum += code[++head % length] - code[tail];
        // 赋值
        ans[i] = sum;
        // 计算尾下标
        tail = ++tail % length;
    }
    return ans;
}
复制代码

提交结果

网络异常,图片无法展示
|

总结

这道题一定要注意判断下标时对 length取余的操作,看我的提交结果就知道很容易出错了,【苦涩】


宁轩
+关注
目录
打赏
0
0
0
0
2
分享
相关文章
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
本文聚焦 MySQL 集群架构中的负载均衡算法,阐述其重要性。详细介绍轮询、加权轮询、最少连接、加权最少连接、随机、源地址哈希等常用算法,分析各自优缺点及适用场景。并提供 Java 语言代码实现示例,助力直观理解。文章结构清晰,语言通俗易懂,对理解和应用负载均衡算法具有实用价值和参考价值。
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
这个AI把arXiv变成代码工厂,快速复现顶会算法!Paper2Code:AI论文自动转代码神器,多智能体框架颠覆科研复现
Paper2Code是由韩国科学技术院与DeepAuto.ai联合开发的多智能体框架,通过规划、分析和代码生成三阶段流程,将机器学习论文自动转化为可执行代码仓库,显著提升科研复现效率。
402 19
这个AI把arXiv变成代码工厂,快速复现顶会算法!Paper2Code:AI论文自动转代码神器,多智能体框架颠覆科研复现
解析局域网内控制电脑机制:基于 Go 语言链表算法的隐秘通信技术探究
数字化办公与物联网蓬勃发展的时代背景下,局域网内计算机控制已成为提升工作效率、达成设备协同管理的重要途径。无论是企业远程办公时的设备统一调度,还是智能家居系统中多设备间的联动控制,高效的数据传输与管理机制均构成实现局域网内计算机控制功能的核心要素。本文将深入探究 Go 语言中的链表数据结构,剖析其在局域网内计算机控制过程中,如何达成数据的有序存储与高效传输,并通过完整的 Go 语言代码示例展示其应用流程。
78 0
18个常用的强化学习算法整理:从基础方法到高级模型的理论技术与代码实现
本文系统讲解从基本强化学习方法到高级技术(如PPO、A3C、PlaNet等)的实现原理与编码过程,旨在通过理论结合代码的方式,构建对强化学习算法的全面理解。
201 10
18个常用的强化学习算法整理:从基础方法到高级模型的理论技术与代码实现
JavaScript 中通过Array.sort() 实现多字段排序、排序稳定性、随机排序洗牌算法、优化排序性能,JS中排序算法的使用详解(附实际应用代码)
Array.sort() 是一个功能强大的方法,通过自定义的比较函数,可以处理各种复杂的排序逻辑。无论是简单的数字排序,还是多字段、嵌套对象、分组排序等高级应用,Array.sort() 都能胜任。同时,通过性能优化技巧(如映射排序)和结合其他数组方法(如 reduce),Array.sort() 可以用来实现高效的数据处理逻辑。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
员工电脑监控系统中的 C# 链表算法剖析-如何监控员工的电脑
当代企业管理体系中,员工电脑监控已成为一个具有重要研究价值与实践意义的关键议题。随着数字化办公模式的广泛普及,企业亟需确保员工对公司资源的合理利用,维护网络安全环境,并提升整体工作效率。有效的电脑监控手段对于企业实现这些目标具有不可忽视的作用,而这一过程离不开精妙的数据结构与算法作为技术支撑。本文旨在深入探究链表(Linked List)这一经典数据结构在员工电脑监控场景中的具体应用,并通过 C# 编程语言给出详尽的代码实现与解析。
83 5
公司监控上网软件架构:基于 C++ 链表算法的数据关联机制探讨
在数字化办公时代,公司监控上网软件成为企业管理网络资源和保障信息安全的关键工具。本文深入剖析C++中的链表数据结构及其在该软件中的应用。链表通过节点存储网络访问记录,具备高效插入、删除操作及节省内存的优势,助力企业实时追踪员工上网行为,提升运营效率并降低安全风险。示例代码展示了如何用C++实现链表记录上网行为,并模拟发送至服务器。链表为公司监控上网软件提供了灵活高效的数据管理方式,但实际开发还需考虑安全性、隐私保护等多方面因素。
83 0
公司监控上网软件架构:基于 C++ 链表算法的数据关联机制探讨
LeetCode力扣第114题:多种算法实现 将二叉树展开为链表
LeetCode力扣第114题:多种算法实现 将二叉树展开为链表

热门文章

最新文章

AI助理
登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问

你好,我是AI助理

可以解答问题、推荐解决方案等