代码随想录二刷博客Day3~Day4

news2024/11/21 0:34:37

707. 设计链表

这道题的解题思路其实就是让我们模拟一个链表的实现:

首先我们先要创建一个内部类作为链表的结点,这个内部类要包含两个元素,一个是val值,一个是指向下一个节点的指针

在构造方法这里我们要初始化一个虚拟头街点和一个链表长度,使用虚拟头节点的好处在于可以统一处理各个节点,不用再单独处理头节点

然后在get方法这里,我们要使用一个cur指针从虚拟头节点开始出发,不断向后遍历直到我们需找到目标的节点,要注意的是,我们的下标值是要比我们cur要走过的步数少一位的,所以我们需要在step这个变量这里加上一位来确保我们能够走到目标的位置上

在处理头插法和尾插法这两个方法时候我们可以直接调用addAtIndex这个方法统一处理

在处理addAtIndex这个方法的时候,我们需要注意的是,我们要找到目标节点的前一个节点进行插入操作,所以根据刚才提到的我们的下标值是要比我们cur要走过的步数少一位的,我们直接让cur走index步,就可以到达目标节点的前一个节点!

同理处理deleteAtIndex这个方法的时候,我们的处理流程适合addAtIndex这个方法一样

具体代码如下

class MyLinkedList {

    class Node{
        int val;
        Node next;

        Node(int val){
            this.val = val;
        }
    }

    Node Dhead;
    int size;

    public MyLinkedList() {
        Dhead = new Node(-1);
        size = 0;
    }
    
    public int get(int index) {
        if(index < 0 || index >= size){
            return -1;
        }
        
        Node cur = Dhead;

        int step = index + 1;

        while(step-- > 0){
            cur = cur.next;
        }

        return cur.val;
    }
    
    public void addAtHead(int val) {
        addAtIndex(0,val);
    }
    
    public void addAtTail(int val) {
        addAtIndex(size,val);
    }
    
    public void addAtIndex(int index, int val) {
        if(index < 0 || index > size){
            return;
        }

        Node node = new Node(val);

        Node cur = Dhead;

        int step = index;

        while(step-- > 0){
            cur = cur.next;
        }


        node.next = cur.next;
        cur.next = node;

        ++size;

    }
    
    public void deleteAtIndex(int index) {
        if(index < 0 || index >= size){
            return;
        }

        Node cur = Dhead;

        int step = index;

        while(step-- > 0){
            cur = cur.next;
        }

        cur.next = cur.next.next;

        size--;
    }
}

206. 反转链表

这道题的思路其实就是从前往后一步一步的修改指向,以给的示例为例子

我们定义两个指针一个pred指向虚拟头节点,一个cur指向pred指向节点的后一个节点

然后使用while循环不断地两个指针向后移动,在移动的过程中cur修改指向让cur.next = pred

在修改完毕后,由于我们的cur的后一个节点已经是pred了,所以我们在一开始就使用curNext来记录cur的后一个节点,在修改完毕后,让后pred走到cur的位置,cur走到curNext的位置上,这样就真正的让两个节点向后移动了

需要注意的时候在最后我们要将head(实际的头节点)的指向修改成空!因为虚拟头节点是我们自己定义的并不属于官方给的例子中

 最后贴上代码

class Solution {
    public ListNode reverseList(ListNode head) {

        if(head == null){
            return null;
        }

        ListNode Dhead = new ListNode();
        Dhead.next = head;
        ListNode pred = Dhead;
        ListNode cur = head;
        
        while(cur != null){
            ListNode curNext = cur.next;
            cur.next = pred;
            pred = cur;
            cur = curNext;
        }

        head.next = null;

        return pred;
    }
}

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

本题的关键就在于本题的题目“如何两两交换链表中的节点”,所以我们的思路就在于交换链表中的相邻的两个节点应该怎么样的交换

我们通过画图的形式来展现我们解题的思路

设置两个指针来记录我们要交换的节点,在我们两两交换完毕以后,需要对后面的链表进行操作,所以我们也需要一个指针来记录后面链表的头节点的位置,以方便我们进行修改指向

我们首先将头节点指向第二个节点,然后将第二个节点的指向修改成指向第一个节点,这样我们的交换就完成了,为了操作后面的链表,我们需要将第一个节点的指向修改成指向后面链表头节点的位置

    public ListNode swapPairs(ListNode head) {
        ListNode Dhead = new ListNode();
        Dhead.next = head;

        ListNode cur = Dhead;

        while(cur.next != null && cur.next.next != null){
            ListNode first = cur.next;
            ListNode second = cur.next.next;   
            ListNode third = cur.next.next.next;
            cur.next = second;
            second.next = first;
            first.next = third;
            cur = first;
        }

        return Dhead.next;
    }

这里需要注意的是while里面的终止条件,由于我们不知道链表的长度是奇数还是偶数,这个就需要注意cur是否会操作空指针,由于我们要交换的链表节点有两个,所以我们要保证两个节点都不为空,所以这里的终止条件就是

cur.next != null && cur.next.next != null 

还有一点我们要注意的是,在交换完以后,我们要让cur走到两两交换节点第一个节点的前一个节点上,所以我们要让 cur = first !

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

思路:怎么样才能删除倒数第N个节点呢?我一开始的思路是让cur指针指向头节点后一直向后走,走到最后一个节点,然后再向前走n步就能进行删除了。但是要注意的是我们这里是单向链表,不能向前走,所以我们只能考虑向后走的方法

假设链表长度是size,那么倒数第1个数就是正数第size个数,倒数第2个数就是正数第(size - 1)个数,以此类推,倒数第n个数就是正数第(size -(n-1))个数。明确这个思路就可以进行删除操作了。

我们首先要统计链表的长度是多少,所以需要一个fast指针来遍历链表,记录链表的长度。然后我们再让另一个指针slow走到n-1个节点的位置上,根据上面推导出来的公式,倒数第n个数就是正数第(size - n )个数。想要从cur节点走到第(size - n )个节点的话,那么步数step = size - n - 1。

明确上面的难点以后代码就好写了,具体代码如下

    public ListNode removeNthFromEnd(ListNode head, int n) {
        if(head == null){
            return null;
        }
        
        ListNode Dhead = new ListNode();
        Dhead.next = head;

        ListNode fast = Dhead;
        ListNode slow = Dhead;

        int len = 0;

        while(fast != null){
            fast = fast.next;
            len++;
        }

        int step = len - n - 1;

        while(step-- > 0){
            slow = slow.next;
        }

        slow.next = slow.next.next;

        return Dhead.next;

    }

面试题 02.07. 链表相交

本题的思路也是使用双指针的思路,假如说我有两个链表(此时不相交),使用两个指针同时指向两个链表的头节点,那么一起走n步,两个指针指向的下标是一样的。

顺着这个思路,假如说两个链表相交,那么我只要让两个指针指向的下标与相交节点的距离相同,然后一起向后走,那么当两个指针指向同一个节点的时候,就能完成本题的要求了。

通过不同的示例我们可以发现,两个链表相交前的长度是不一样的,那么我们为了让他们的起始下标一致,可以让长的链表走n步,其中这个n步就对应着两个链表长度的差值,这样就可以让两个指针指向的下标与相交节点的距离相同了!

最后贴上代码

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode curA = headA;
        ListNode curB = headB;

        int stepA = 0;
        int stepB = 0;

        while(curA != null){
            curA = curA.next;
            ++stepA;
        }

        curA = headA;

        while(curB != null){
            curB = curB.next;
            ++stepB;
        }

        curB = headB;

        int step = Math.abs(stepA - stepB);

        if(stepA > stepB){
            while(step-- != 0){
                curA = curA.next;
            }
        }else if(stepA < stepB){
            while(step-- != 0){
                curB = curB.next;
            }
        }

        while(curA != null && curB != null && curA != curB){
            curA = curA.next;
            curB = curB.next;
        }

        return curA;
    }
}

142. 环形链表 II

这道题的解题思路分两个步骤,首先确认链表是否有环,其次确认环的入口节点在哪

我们首先解决第一个问题“确认链表是否有环” 

对于这个问题,我们使用双指针的方式来解决这个问题,我们让慢指针每次都走一步来遍历链表,让快指针每次走两步来遍历链表。如果链表有环,那么两者一定能相遇,因为如果有环,当慢指针刚刚进入环内,快指针已经转了n(n >= 1)圈了。以慢指针为参考系,慢指针不动,快指针相对自己在圈内每次前进一步,那么最后一定是可以相遇的!

为什么不能让快指针每次走三步,四步或者更多步?还是回到参考系这个问题上,以慢指针为参考系,慢指针不动,快指针相对自己在圈内每次前进一步,那么最后一定是可以相遇的!但是快指针相对自己在圈内每次前进两步,三步,那么很有可能快指针每次移动都越过慢指针,为了确保一定能相遇我们使用快指针相对前进一步的方式进行移动

回到第二个问题。确认了链表内有环,该如何确认入口的位置呢?

我们首先要知道的是,在慢指针走过的第一圈里面就可以遇到快指针

我们可以画一个图来证明

我们推到快指针和慢指针相遇的路程的时候可以有以下假设:

头节点到入口节点的位置距离为 x

入口节点到两个节点相遇的位置距离为 y

两个节点相遇的位置到入口的位置距离为 z

那么开始下面的数学推导

快指针走过的距离 s1 = x + y + n*(y + z) 

慢指针走过的距离 s2 = x + y

时间相同,快指针的速度是慢指针的两倍

所以得到 v1 = s1 / t = 2*v2 = s2 / t

即 x = (n-1)*(y+z) + z

也就说当我们设置两个指针,一个指向头节点,一个指向相遇处,那么两者是一定可以相遇,相遇的地方就是我们的入口处!

结束推导

开始写代码

public class Solution {
    public ListNode detectCycle(ListNode head) {
        if(head == null || head.next == null){
            return null;
        }
        
        ListNode slow = head;
        ListNode fast = head;

        while(fast != null && fast.next != null){
            fast = fast.next.next;
            slow = slow.next;

            if(slow == fast){
                slow = head;
                while(slow != fast){
                    slow = slow.next;
                    fast = fast.next;
                }
                return slow;
            }
        }
        if(fast == null || fast.next == null){
            fast = null;
        }
        return fast;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/851280.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

解决页面是Whitelabel Error Page方法之一

在网上随便一搜都能搜到很多当页面是Whitelabel Error Page时的解决方法&#xff0c;这里就不一一赘述了&#xff0c;如果试过了各种方法都不能解决&#xff0c;可以看看我这个解决方法&#xff0c;看看是不是和我的情况相同 我这个bug出现的前提是&#xff0c;SpringBoot项目…

三种方法实现tab栏切换(CSS方法、JS方法、Vue方法)

一、需求 给下图的静态页面添加tab栏切换效果 二、CSS方法 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"v…

人工智能的未来:探索下一代生成模型

推荐&#xff1a;使用 NSDT场景编辑器 助你快速搭建可编辑的3D应用场景 生成式 AI 目前能够做什么&#xff0c;以及探索下一波生成式 AI 模型需要克服的当前挑战&#xff1f; 如果你跟上科技世界的步伐&#xff0c;你就会知道生成式人工智能是最热门的话题。我们听到了很多关于…

C语言案例 判断是否为回文数-06

题目&#xff1a;随机输入一个5位数&#xff0c;判断它是不是回文数 步骤一&#xff1a;定义程序的目标 编写C程序&#xff0c;随机输入一个5位数&#xff0c;判断它是不是回文数 步骤二&#xff1a;程序设计 原理&#xff1a;即12321是回文数&#xff0c;个位与万位相同&#…

echarts甘特图 一个值多条线

先看图 这里我们用到的是 series &#xff1a;type:custom 自定义&#xff0c;但是这里我遇到一个问题&#xff0c;就是不过你在series里push多少数据&#xff0c;图表上显示的都是在同一水平线&#xff0c;用了好多方法都不好使&#xff0c; renderItem: (params, api) >…

ModaHub魔搭社区——GPTCache 的工作原理

GPTCache 模块化的架构设计方便用户定制个性化语义缓存。每个模块都提供多种选择,适合各种应用场景。 大语言模型适配器: 适配器将大语言模型请求转换为缓存协议,并将缓存结果转换为 LLM 响应。适配器方便轻松集成所有大语言模型,并可灵活扩展。GPTCache 支持多种大语言模型…

【雕爷学编程】Arduino动手做(199)---8x32位WS2812B全彩屏模块4

37款传感器与模块的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&#x…

如何构建高级的浅色和深色主题切换

通过这个实例我们主要是掌握如下知识点 灵活使用 CSS 变量使用 JS 获取 CSS 变量灵活使用 CSS 的transform和transition属性 效果图 实现页面布局 从效果图我们首先可以实现页面的大致布局&#xff0c;具体的代码如下&#xff1a; <h2 class"main-title">主…

接口测试总结分享(http与rpc)

接口测试是测试系统组件间接口的一种测试。接口测试主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点。测试的重点是要检查数据的交换&#xff0c;传递和控制管理过程&#xff0c;以及系统间的相互逻辑依赖关系等。 一、了解一下HTTP与RPC 1. HTTP&#xff08;H…

Stable Diffuion webui Mac版本安装过程

系统环境 操作系统&#xff1a;MacOS Ventura13.5 芯片&#xff1a;Apple M2 Max Python: 3.10 安装前置准备 git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.git注意事项&#xff1a;修改源码内全部 git clone 链接&#xff0c;设置代理 https://ghpr…

C++——模板简要介绍

首先给出一个栈的类 class Stack { public:Stack(size_t capacity 4)//不传入值则就默认4个空间&#xff0c;&#xff08;构造函数&#xff09;{cout << "Stack(size_t n 4)" << endl;_a new DataType[capacity];_capacity capacity;_top 0;}~Stac…

【雕爷学编程】Arduino动手做(199)---8x32位WS2812B全彩屏模块3

37款传感器与模块的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&#x…

【Vue3】插槽全家桶

插槽&#xff08;Slots&#xff09;是 Vue.js 框架中的一个功能&#xff0c;允许在组件内部预留一些可替换的内容。通过插槽&#xff0c;可以给父组件填充模板代码&#xff0c;让父组件向子组件传递自定义的内容&#xff0c;以便在子组件中进行展示或处理。 1. 匿名插槽 Son.…

使用chatGPT应用于人力资源行业

在当今快速发展的技术环境中&#xff0c;人力资源专业人员保持技术领先和意识领先至关重要。采用创新工具&#xff0c;如OpenAI的ChatGPT&#xff0c;充分利用其强大的力量&#xff0c;可能会改变整个行业的游戏规则。 提高招聘流程的人力效率 如果能够实现招聘流程自动化&am…

[HDBits] Exams/m2014 q4h

Implement the following circuit: module top_module (input in,output out);assign outin; endmodule

halcon 学习笔记

图像的参数 图形参数 Iconic, 包括 image, region, XLD 1.1 image 图像由一个或者多个通道组成&#xff0c;是大小相同的矩阵&#xff0c;包含各种像素类型的灰度值 在图像显示界面&#xff0c;按ctrl健&#xff0c;可以查看当前的像素值 灰度图 一个通道像素点存放在一个矩…

文件的加密与解密

将文件内容读入缓冲区&#xff0c;再将缓冲区中接收到的所有数据每一个数据在原来基础上加10&#xff0c;再传回文件中&#xff0c;解密减10即可。&#xff08;在读操作后将文件指针偏移到文件开头进行写操作&#xff09;

基于springboot+vue的健身房管理系统_bgnk6

随着计算机技术发展&#xff0c;计算机系统的应用已延伸到社会的各个领域&#xff0c;大量基于网络的广泛应用给生活带来了十分的便利。所以把健身房管理与现在网络相结合&#xff0c;利用计算机搭建健身房管理系统&#xff0c;实现健身房的信息化。则对于进一步提高健身房管理…

【雕爷学编程】Arduino动手做(201)---DFRobot 行空板02

37款传感器与模块的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&#x…

Vue.js2+Cesium1.103.0 六、标绘与测量

Vue.js2Cesium1.103.0 六、标绘与测量 点&#xff0c;线&#xff0c;面的绘制&#xff0c;可实时编辑图形&#xff0c;点击折线或多边形边的中心点&#xff0c;可进行添加线段移动顶点位置等操作&#xff0c;并同时计算出点的经纬度&#xff0c;折线的距离和多边形的面积。 De…