leetcode刷题之链表相关问题(js)

news2024/11/27 8:22:24

21.合并两个有序链表

在这里插入图片描述

var mergeTwoLists = function(list1, list2) {
    if(list1==null) return list2
    if(list2==null) return list1
    let newHead = new ListNode(0,null) //创建一个虚拟节点
    let cur = newHead
    let cur1 = list1,cur2 = list2
    while(cur1&&cur2){
        if(cur1.val<=cur2.val){
            cur.next = cur1
            cur = cur1
            cur1 = cur1.next
        }else{
            cur.next = cur2
            cur = cur2
            cur2 = cur2.next
        }
    }
    while(cur1){
        cur.next = cur1
        cur = cur1
        cur1 = cur1.next
    }
    while(cur2){
        cur.next = cur2
        cur = cur2
        cur2 = cur2.next
    }
    return newHead.next
};

203.移除链表元素

在这里插入图片描述

方法一:新建虚拟节点+pre

var removeElements = function(head, val) {
    if(head==null) return null
    let newHead = new ListNode(-1)
    newHead.next = head
    let cur = head,pre = newHead
    while(cur){
        if(cur.val==val){
            cur = cur.next
            pre.next = cur
        }else{
            pre = cur
            cur = cur.next
        }
    }
    return newHead.next
};

方法二:参考大佬的写法

var removeElements = function(head, val) {
    //设置一个虚拟头节点
    let newHead = new ListNode(0,head)
    let cur = newHead
    while(cur.next){
        if(cur.next.val==val){
            cur.next = cur.next.next
            continue
        }
        cur = cur.next
    }
    return newHead.next
};

707.设计链表

//节点的构造函数
class ListNode {
    constructor(val,next){
        this.val = val
        this.next = next
    }
}
var MyLinkedList = function() {
    //链表的初始化
    this.size = 0
    this.head = null
    this.tail = null
};

/** 
 * @param {number} index
 * @return {number}
 */
//用来获取某个索引的结点
MyLinkedList.prototype.getNode = function(index){
    if(index<0||index>=this.size) return null
    let cur = new ListNode(0,this.head) //创建一个虚拟节点
    while(index-- >=0){
        cur = cur.next
    }
    return cur
}
//获取某个index的值
MyLinkedList.prototype.get = function(index) {
    if(index<0||index>=this.size) return -1
    return this.getNode(index).val
};
/** 
 * @param {number} val
 * @return {void}
 */
MyLinkedList.prototype.addAtHead = function(val) {
    let newHead = new ListNode(val,this.head)
    this.head = newHead
    //判断尾巴结点
    if(!this.tail){
        this.tail = this.head
    }
    this.size++
};

/** 
 * @param {number} val
 * @return {void}
 */
MyLinkedList.prototype.addAtTail = function(val) {
    let newTail = new ListNode(val,null)
    this.size++
    if(this.tail){
        this.tail.next = newTail
        this.tail = newTail
        return
    }
    this.head = newTail
    this.tail = newTail
    
};

/** 
 * @param {number} index 
 * @param {number} val
 * @return {void}
 */
MyLinkedList.prototype.addAtIndex = function(index, val) {
    if(index>this.size) return
    if(index<=0){
        this.addAtHead(val)
        return
    }
    if(index==this.size){
        this.addAtTail(val)
        return
    }
    let preNode = this.getNode(index-1)
    preNode.next = new ListNode(val,preNode.next)
    this.size++
};

/** 
 * @param {number} index
 * @return {void}
 */
MyLinkedList.prototype.deleteAtIndex = function(index) {
    if(index<0||index>=this.size) return  //这里已经排除空的情况了
    if(index==0){
        this.head = this.head.next
        //处理尾巴结点
        if(index==this.size-1){
            this.tail = this.head
        }
        this.size--
        return
    }
    //获取上一个结点
    let preNode = this.getNode(index-1)
    preNode.next = preNode.next.next
    if(index==this.size-1){
        this.tail = preNode
    }
    this.size--
};

/**
 * Your MyLinkedList object will be instantiated and called as such:
 * var obj = new MyLinkedList()
 * var param_1 = obj.get(index)
 * obj.addAtHead(val)
 * obj.addAtTail(val)
 * obj.addAtIndex(index,val)
 * obj.deleteAtIndex(index)
 */

206.反转链表

在这里插入图片描述

方法一:头插法

var reverseList = function(head) {
    //头插法
    if(head==null||head.next==null) return head
    //创建一个虚拟节点
    let newHead = new ListNode(-1,null)
    let cur = head
    let nextNode = null
    while(cur){
        //保留cur的下一个节点
        nextNode = cur.next
        cur.next  = newHead.next
        newHead.next = cur
        //然后找回nextNode
        cur = nextNode
    }
    return newHead.next
};

递归法一

var reverseList = function(head) {
//这个递归式从后往前进行翻转
    const helper = curNode =>{
        //递归跳出的条件 要考虑空链表的情况所以要加上curNode==null这一判断条件
        if(curNode==null||curNode.next==null) return curNode
        //p相当于是最后一个结点
        let p = helper(curNode.next)
        // if(p!==null){   这里的if语句可以去掉了 只要链表不是空的 那么curNode.next都可以条粗递归
            curNode.next.next = curNode
            curNode.next = null
        // }
        return p
    }
    return helper(head)
};

递归法二

var reverseList = function(head) {
    //这种方法是从第一个结点开始向前翻转,一直到最后一个结点
    const helper = (pre,head) =>{
        //递归跳出的条件
        if(head==null) return pre
        let temp = head.next
        head.next = pre
        pre = head
        //向后进行遍历
        return helper(pre,temp)    //整个递归的最后返回值是pre 也就是原链表的最后一个结点
    }
    return helper(null,head)
};

使用栈来进行翻转

var reverseList = function(head) {
    //使用栈 将所有的结点全都压入栈中 然后创建一个虚拟结点 然后栈中的结点出栈
    if(head==null||head.next==null) return head
    let stack = []
    let cur = head
    //全部入栈
    while(cur){
        stack.push(cur)
        cur = cur.next
    }
    let newNode = new ListNode(0,null)
    let curNode = newNode
    while(stack.length){
        let node = stack.pop()
        curNode.next = node
        curNode = node
    }
    curNode.next = null//防止最后形成一个圈
    return newNode.next
};

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

在这里插入图片描述

使用队列进行交换

var swapPairs = function(head) {
    if(head==null||head.next==null) return head
    let queue = []
    let cur = head
    while(cur){
        queue.push(cur)
        cur = cur.next
    }
    let newNode = new ListNode(0,null)
    let now = newNode
    //当队列中有偶数个结点
    while(queue.length>=2){
        let node1 = queue.shift()
        let node2 = queue.shift()
        //在使用队列或者栈,我试了好多次 在出栈之前将 每个节点的next指针置为空 这样才能避免
        // node1.next = null
        // node2.next = null
        now.next = node2
        now = node2
        now.next = node1
        now = node1
    }
    //当只剩下一个节点了
    while(queue.length==1){
        let node1 = queue.shift()
        // node1.next = null
        now.next = node1
        now = node1
    }
    now.next = null   //修改一下 将最后一个结点的next 置为空即可
    return newNode.next
};

原地进行交换

var swapPairs = function(head) {
    //原地进行交换
    if(head==null||head.next==null) return head
    //进行交换
    let newHead = new ListNode(0,head) //创建一个虚拟节点
    let curNode = newHead.next
    let pre = newHead
    while(curNode&&curNode.next){
        let nextNode = curNode.next.next //保存结点
        pre.next = curNode.next
        pre = curNode
        curNode.next.next = curNode
        curNode.next = nextNode
        curNode = nextNode
    }
    //最后只剩下一个结点 就不用进行交换了
    return newHead.next
};

递归实现

参考

var swapPairs = function(head) {
    //和翻转链表很类似
    const helper = head =>{ //判断条件head==null是用来判断链表是否为空的
        if(head==null||head.next==null) return head
        //每次返回的节点是处理好之后的
        let nextNode = head.next
        head.next = helper(nextNode.next)
        nextNode.next = head
        return nextNode
    }
    return helper(head)
};

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

在这里插入图片描述

方法一:使用两次循环找到第n个节点的位置

var removeNthFromEnd = function(head, n) {
    //方法一:从头开始进行遍历找到第n个结点
    if(head==null) return head
    let sum = 1 //统计链表的总长度
    let cur = head
    while(cur.next){
        sum++
        cur = cur.next
    }
    //如果链表的长度不够
    if(n>sum) return head
    if(n==sum){
         return head.next
    }
    //也即是删除第 sum-n+1个结点  需要找它前面的结点
    let i = 1
    cur = head
    while(i<sum-n){
        i++
        cur = cur.next
    }
    cur.next = cur.next.next
    return head
};

方法二:使用快慢指针

var removeNthFromEnd = function(head, n) {
    //使用快慢指针 当fast指针走了n个位置之后 slow指针开始走动 当fast走到空的时候 slow所指的位置就是倒数第n个位置
    if(head==null) return head
    let slow = head, fast = head
    let i = 1 //记录位置
    //首先fast指针要移动到第n+1个位置
    while(fast.next&&i<=n){
        i++
        fast = fast.next
    }
    if(i<n) return head //也就是说链表的长度小于n
    if(i==n) return head.next//链表的长度正好是n
    //链表的长度够了 那么slow fast同时向前移动
    while(fast.next){
        fast = fast.next
        pre = slow
        slow = slow.next  //slow正好是要删除的位置的前面
    }
    slow.next = slow.next.next
    return head
};

面试题02.07.链表相交

在这里插入图片描述

var getIntersectionNode = function(headA, headB) {
    if(headA==null||headB==null) return null
    //首先找出两个链表的长度
    let cur = headA
    let sumA = 1,sumB = 1
    while(cur.next){
        sumA++
        cur = cur.next
    }
    cur = headB
    while(cur.next){
        sumB++
        cur = cur.next
    }
    // console.log(sumA,sumB)
    let len = Math.abs(sumA - sumB)
    // console.log(len,'changdu ')
    if(sumA>sumB){
        //A链表先去移动len个位置
        while(len-- >0){
            headA = headA.next
        }
    }
    if(sumA<sumB){
        while(len-- >0){
            headB = headB.next
        }
    }
    // console.log(headA,headB,'jiedian')
    //移动完成之后 a b 后面的长度相同
    while(headA){
        if(headA==headB) return headA
        headA = headA.next
        headB = headB.next
    }
    return null
};

141.环形链表

在这里插入图片描述

使用快慢指针

var hasCycle = function(head) {
    //使用快慢指针 slow每次走一个位置 fast每次走两个位置 如果链表中有圈 那么fast一定会转一圈然后赶上slow,可以这么理解,slow相对于的fast的位置是不变的,fast相对于slow每次走一个位置,这样如果链表中有圈,那么fast一定可以回到原来的位置
    if(head==null||head.next==null) return false
    let slow = head,fast = head
    while(fast.next){
        fast = fast.next
        if(fast.next){
            fast = fast.next
        }
        slow = slow.next
        // if(slow==fast){ //这样会出现错误 由于上面 进行while循环的时候,fast可以只走一个位置,而此时slow也走一个位置 这样即使是一条链 也会相等
        //     return true
        // }
        if(fast.next==slow){
            return true
        }
    }
    return false
};

快慢指针修改

var hasCycle = function(head) {
    //使用快慢指针 slow每次走一个位置 fast每次走两个位置 如果链表中有圈 那么fast一定会转一圈然后赶上slow,可以这么理解,slow相对于的fast的位置是不变的,fast相对于slow每次走一个位置,这样如果链表中有圈,那么fast一定可以回到原来的位置
    if(head==null||head.next==null) return false
    let slow = head,fast = head
    while(fast&&fast.next){
        fast = fast.next.next
        slow = slow.next
        if(slow==fast){
            return true
        }
    }
    return false
};

142.环形链表2

方法一:使用map保存节点信息

var detectCycle = function(head) {
    if(head==null||head.next==null) return null
    //使用map对象来保存遍历过的结点
    let map = new Map()
    let cur = head
    while(cur.next){
        if(map.has(cur)){
            //如果map中有这个结点 那么这个结点就是圈的起点
            return cur
        }else{
            map.set(cur,1)
        }
        cur = cur.next
    }
    return null
};

方法二:快慢指针

在这里插入图片描述
思路:
①当slow指针和fast指针相遇的时候,slow走了x+y;fast走了x+y+n(y+z);
②由于fast的速度是slow的2倍,所以有2(x+y)=x+y=n(y+z)
③移项得x = n (y + z) - y
④令n=1得到x=z,也即是当slow和fast第一次相遇的时候,如果这时候有一个结点temp从head出发,那么temp和slow同时移动,当temp==slow的时候,temp就是入口结点

参考代码随想录

var detectCycle = function(head) {
    if(head==null||head.next==null) return null
    let slow = head,fast = head
    while(fast&&fast.next){
        fast = fast.next.next
        slow = slow.next
        if(slow==fast){
            //既然是有环的 那么就要去找这个环的入口
            fast = head
            while(fast!==slow){
                fast = fast.next
                slow = slow.next
            }
            return fast
        }
    }
    return null //没有圈
};

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

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

相关文章

PowerToys Windows 工具集

Microsoft PowerToys | Microsoft Learn Microsoft PowerToys&#xff1a;用于自定义 Windows 的实用工具 项目2023/04/1918 个参与者 反馈 Microsoft PowerToys 是一组实用工具&#xff0c;可帮助高级用户调整和简化其 Windows 体验&#xff0c;从而提高工作效率。 安装 …

Unity之效应器

主要作用&#xff1a;在一个区域内让游戏对象受到力和扭矩力的作用 1、创建一个精灵&#xff08;绿色区域&#xff09; 2、为其添加碰撞器&#xff08;要将Used By Effector和is Trigger打钩&#xff09; 3、添加效应器组件 4、区域效应器参数 Use Collider Mask&#xff1a;…

第3章 Class and Object

构造函数 Guaranteed initialization with the constructor使用构造函数保证初始化 • If a class has a constructor, the compiler automatically calls that constructor at the point an object is created, before client programmers can get their hands on the o…

Solidity基础五

暂时的一事无成也代表将来万事皆有可能&#xff01; 目录 一、对Solidity文件的理解 二、Solidity的导sol文件&#xff08;库、合约&#xff09; 三、Solidity的继承 1.继承的分类 2.继承的可见性 3.父合约构造函数的传参 4.调用父合约成员 5.重写 四、Solidity的抽象…

Solidity基础八

别慌&#xff0c;月亮也在大海某处迷茫 目录 一、Solidity 编程风格 1. 代码布局 2. 代码中各部分的顺序 3. 命名约定 二、Solidity 智能合约编写过程 1. solidity Hello World 2. 版本声明 3. 导入声明 4. 合约声明 三、Solidity 合约结构 智能合约 Test 四、So…

Solidity基础六

生活本来就是平凡琐碎的&#xff0c;哪有那么多惊天动地的大事&#xff0c;快乐的秘诀就是不管对大事小事都要保持热情 目录 一、Solidity的特殊变量(全局) 二、Solidity的不可变量 immutable的赋值方式 三、Solidity的事件与日志 事件和日志加深理解 四、Solidity的异常…

EMLP2021 | Google大模型微调经典论文prompt tuning

一、概述 title&#xff1a;The Power of Scale for Parameter-Efficient Prompt Tuning 论文地址&#xff1a;https://arxiv.org/abs/2104.08691 代码&#xff1a;GitHub - google-research/prompt-tuning: Original Implementation of Prompt Tuning from Lester, et al, …

系列一、RuoYi前后端分离(登录密码加密)

一、部署前后端服务 http://doc.ruoyi.vip/ruoyi-vue/ 二、现象 若依前后端环境分离版本&#xff0c;本地部署好前后端环境后&#xff0c;访问登录接口密码是明文的&#xff0c;这样显然hi不安全的&#xff0c;如下图所示&#xff1a; 三、解决方法 3.1、加密流程 ①、后端…

Linux-0.11 文件系统namei.c详解

Linux-0.11 文件系统namei.c详解 模块简介 namei.c是整个linux-0.11版本的内核中最长的函数&#xff0c;总长度为700行。其核心是namei函数&#xff0c;即根据文件路径寻找对应的i节点。 除此以外&#xff0c;该模块还包含一些创建目录&#xff0c;删除目录&#xff0c;创建目…

Day2:Windows网络编程-TCP

今天开始进入Windows网络编程的学习&#xff0c;在学习的时候总是陷入Windows复杂的参数&#xff0c;纠结于这些。从老师的讲解中&#xff0c;这些内容属于是定式&#xff0c;主要学习写的逻辑。给自己提个醒&#xff0c;要把精力放在正确的位置&#xff0c;不要无端耗费精力。…

【JavaScript】文件分片上传

文章目录 普通文件上传分片上传整体流程技术点分析文件选择方式隐藏input框&#xff0c;自定义trigger拖拽上传 分片动态分片 计算哈希workerrequestIdleCallback抽样 请求并发控制进度展示手动中止/暂停 合并流式并发合并 反思分片命名问题并发控制代码实现的问题 参考文献 普…

ChatGPT桌面客户端支持gpt4模型,附使用说明

#软件核心功能&#xff1a; 1、支持OpenAI官方秘钥及API2D双秘钥使用&#xff1b;如果全局魔法&#xff0c;可以自己用官方秘钥&#xff1b;没魔法国内可直接使用API2D秘钥&#xff1b; 2、内置GPT4模型选项&#xff0c;如果你的官方秘钥支持可直接使用&#xff1b;你也可以注册…

【Labview如何显示数据库表格中的内容】

Labview如何显示数据库表格中的内容 前提操作思路框图 前提 已经成功将数据库与Labview相连接&#xff0c;若还没有链接可以查看&#xff1a;Labview与SQL Server互联 进行操作 操作 思路 首先创建一个表格控件&#xff0c;通过一个按钮启动程序&#xff0c;通过程序调用数…

SAP MM 根据采购订单反查采购申请

如何通过采购订单号查询到其前端的采购申请号。 首先从采购申请的相关报表着手&#xff0c;比如ME5A, 发现它是可以满足需求的。 例如&#xff1a;如下的采购订单&#xff0c; 该订单是由采购申请10003364转过来的。 如果想通过这个采购订单找到对应的采购申请&#xff0c;在…

Packet Tracer – 配置命名标准 IPv4 ACL

Packet Tracer – 配置命名标准 IPv4 ACL 地址分配表 设备 接口 IP 地址 子网掩码 默认网关 R1 F0/0 192.168.10.1 255.255.255.0 N/A F0/1 192.168.20.1 255.255.255.0 N/A E0/0/0 192.168.100.1 255.255.255.0 N/A E0/0/1 192.168.200.1 255.255.2…

第五十五天学习记录:C语言进阶:动态内存管理Ⅲ

柔性数组 C99中&#xff0c;结构中的最后一个元素允许是未知大小的数组&#xff0c;这就叫做柔性数组成员。 柔性数组的特点&#xff1a; 。结构体中的柔性数组成员前面必须至少有一个其他成员。 。sizeof返回的这种结构大小不包括柔性数组的内存。 。包含柔性数组成员的结构…

【C++学习】智能指针

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《C学习》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 智能指针 &#x1f96e;智能指针&#x1f362;为什么需要智能指针&#x1f362;RAII &#x1f96e;au…

chatgpt赋能python:Python自动开机:提高效率的必备工具

Python 自动开机&#xff1a;提高效率的必备工具 随着科技的发展&#xff0c;计算机在我们的日常生活中扮演了越来越重要的角色。为了提高工作效率和使用体验&#xff0c;越来越多的人开始探索利用自动化工具来简化日常操作。 Python 称得上是自动化领域中的一把利器。通过代…

SAP-MM费用类采购通过物料组确定科目

一、WRX的配置&#xff0c;分两类GR/IR科目&#xff1a; 1、做库存管理物料的GR/IR科目&#xff0c;需要配置评估类&#xff0c;此评估类就是物料主数据里配置的评估类&#xff1b; 2、非库存管理费用化物料的GR/IR科目&#xff0c;如固定资产、办公用品、低值易耗品等等&#…

chatgpt赋能python:Python生成C代码:如何用Python快速高效地生成C代码

Python生成C代码&#xff1a;如何用Python快速高效地生成C代码 在现代编程中&#xff0c;有许多原因需要编写C代码。C是一种高性能语言&#xff0c;它允许程序员直接操作计算机的硬件。但是&#xff0c;编写C代码需要花费大量的时间和精力。幸运的是&#xff0c;Python可以帮助…