0113 链表Day2

news2024/12/26 14:04:52

剑指 Offer 06. 从尾到头打印链表

输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。

示例 1

输入:head = [1,3,2]

输出:[2,3,1]

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public int[] reversePrint(ListNode head) {

    }
}

解题思路:

方法一:递归法
利用递归,先递推至链表末端;回溯时,依次将节点值加入列表,即可实现链表值的倒序输出。

递归解析:
终止条件: 当 head == None 时,代表越过了链表尾节点,则返回空列表;
递推工作: 访问下一节点 head.next ;
回溯阶段:将当前节点值 head.val 加入列表 tmp ;

代码如下:

class Solution {
    ArrayList<Integer> tmp = new ArrayList<Integer>();
    public int[] reversePrint(ListNode head) {
        recur(head);
        int[] res = new int[tmp.size()];
        for(int i = 0; i < res.length; i++)
            res[i] = tmp.get(i);
        return res;
    }
    void recur(ListNode head) {
        if(head == null) return;
        recur(head.next);
        tmp.add(head.val);
    }
}

方法二:辅助栈法
链表只能 从前至后 访问每个节点,而题目要求 倒序输出 各节点值,这种 先入后出 的需求可以借助 栈 来实现。

算法流程:
入栈: 遍历链表,将各节点值 push 入栈。
出栈: 将各节点值 pop 出栈,存储于数组并返回。

代码如下:

class Solution {
    public int[] reversePrint(ListNode head) {
        LinkedList<Integer> stack = new LinkedList<Integer>();
        while(head != null) {
            stack.addLast(head.val);
            head = head.next;
        }
        int[] res = new int[stack.size()];
        for(int i = 0; i < res.length; i++)
            res[i] = stack.removeLast();
    return res;
    }
}

剑指 Offer 24. 反转链表 

 定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。

示例:

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {

    }
}

解题思路: 

方法一:迭代(双指针)

考虑遍历链表,并在访问各节点时修改 next 引用指向。

代码如下:

class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode cur = head, pre = null;
        while(cur != null) {
            ListNode tmp = cur.next; // 暂存后继节点 cur.next
            cur.next = pre;          // 修改 next 引用指向
            pre = cur;               // pre 暂存 cur
            cur = tmp;               // cur 访问下一节点
        }
        return pre;
    }
}

方法二:递归
考虑使用递归法遍历链表,当越过尾节点后终止递归,在回溯时修改各节点的 next 引用指向。

recur(cur, pre) 递归函数:
终止条件:当 cur 为空,则返回尾节点 pre (即反转链表的头节点);
递归后继节点,记录返回值(即反转链表的头节点)为 res ;
修改当前节点 cur 引用指向前驱节点 pre ;
返回反转链表的头节点 res ;


reverseList(head) 函数:
调用并返回 recur(head, null) 。传入 null 是因为反转链表后, head 节点指向 null ;

 

代码如下:

class Solution {
    public ListNode reverseList(ListNode head) {
        return recur(head, null);    // 调用递归并返回
    }
    private ListNode recur(ListNode cur, ListNode pre) {
        if (cur == null) return pre; // 终止条件
        ListNode res = recur(cur.next, cur);  // 递归后继节点
        cur.next = pre;              // 修改节点引用指向
        return res;                  // 返回反转链表的头节点
    }
}

剑指 Offer 35. 复杂链表的复制 

请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。

示例 1:

输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]


示例 2:

输入:head = [[1,1],[2,1]]
输出:[[1,1],[2,1]]

/*
// Definition for a Node.
class Node {
    int val;
    Node next;
    Node random;

    public Node(int val) {
        this.val = val;
        this.next = null;
        this.random = null;
    }
}
*/
class Solution {
    public Node copyRandomList(Node head) {
        
    }
}

解题思路:

方法一:哈希表
利用哈希表的查询特点,考虑构建 原链表节点 和 新链表对应节点 的键值对映射关系,再遍历构建新链表各节点的 next 和 random 引用指向即可。

算法流程:
1.若头节点 head 为空节点,直接返回 null ;
2.初始化: 哈希表 dic , 节点 cur 指向头节点;
3.复制链表:
        1.建立新节点,并向 dic 添加键值对 (原 cur 节点, 新 cur 节点) ;
        2.cur 遍历至原链表下一节点;
4.构建新链表的引用指向:
        1.构建新节点的 next 和 random 引用指向;
        2.cur 遍历至原链表下一节点;
5.返回值: 新链表的头节点 dic[cur] ;

代码如下:

class Solution {
    public Node copyRandomList(Node head) {
        if(head == null) return null;
        Node cur = head;
        Map<Node, Node> map = new HashMap<>();
        // 3. 复制各节点,并建立 “原节点 -> 新节点” 的 Map 映射
        while(cur != null) {
            map.put(cur, new Node(cur.val));
            cur = cur.next;
        }
        cur = head;
        // 4. 构建新链表的 next 和 random 指向
        while(cur != null) {
            map.get(cur).next = map.get(cur.next);
            map.get(cur).random = map.get(cur.random);
            cur = cur.next;
        }
        // 5. 返回新链表的头节点
        return map.get(head);
    }
}

方法二:拼接 + 拆分
考虑构建 原节点 1 -> 新节点 1 -> 原节点 2 -> 新节点 2 -> …… 的拼接链表,如此便可在访问原节点的 random 指向节点的同时找到新对应新节点的 random 指向节点。

算法流程:

1.复制各节点,构建拼接链表
2.构建新链表各节点的 random 指向
3.拆分原 / 新链表
4.返回新链表的头节点 res 即可

代码如下:

class Solution {
    public Node copyRandomList(Node head) {
        if(head == null) return null;
        Node cur = head;
        // 1. 复制各节点,并构建拼接链表
        while(cur != null) {
            Node tmp = new Node(cur.val);
            tmp.next = cur.next;
            cur.next = tmp;
            cur = tmp.next;
        }
        // 2. 构建各新节点的 random 指向
        cur = head;
        while(cur != null) {
            if(cur.random != null)
                cur.next.random = cur.random.next;
            cur = cur.next.next;
        }
        // 3. 拆分两链表
        cur = head.next;
        Node pre = head, res = head.next;
        while(cur.next != null) {
            pre.next = pre.next.next;
            cur.next = cur.next.next;
            pre = pre.next;
            cur = cur.next;
        }
        pre.next = null; // 单独处理原链表尾节点
        return res;      // 返回新链表头节点
    }
}

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

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

相关文章

通过源码来理解Cglib与JDK动态代理

最近在阅读到了Spring源码对于两种动态代理使用在不同场景下的使用&#xff0c;两种方式各有利弊写一篇文加深自己的认识。文中对于源码的涉及较少&#xff0c;更多的是作者自己的理解和举例&#xff0c;然后通过部分源码验证。 首先看两个面试经常会遇到的关于Spring的问题&a…

纳尼?华为首席架构师只用434页笔记,就将网络协议给拿下了

不管是前端还是后端&#xff0c;几乎所有的程序运行都会涉及到网络协议。10 个程序员里面&#xff0c;10 个都说自己学过网络协议&#xff0c;9 个说自己懂网络协议。但真正面试的时候&#xff0c;能回答出相关问题的&#xff0c;可能只有两三个。 金九银十跳槽热季&#xff0…

七、【React-Router6】路由传参 之 search

文章目录1、routes.js2、Message.jsx3、Detail.jsx4、Result5、另外一个可以获取 search 的新 Hook &#xff1a;useLocation项目修改自 上一节 的 Demo 1、routes.js import { Navigate } from react-router-dom import About from ../components/About import Home from ../…

【D3.js】1.18-给 D3 标签添加样式

title: 【D3.js】1.18-给 D3 标签添加样式 date: 2022-12-02 14:44 tags: [JavaScript,CSS,HTML,D3.js,SVG] 标签也可以添加样式。 一、学习目标 如何设置字体大小&#xff1f; .attr(“font-size”,25) 如何填充颜色&#xff1f; .attr(“fill”,“red”) 二、题目 将 text 元…

LeetCode简单题之不同的平均值数目

题目 给你一个下标从 0 开始长度为 偶数 的整数数组 nums 。 只要 nums 不是 空数组&#xff0c;你就重复执行以下步骤&#xff1a; 找到 nums 中的最小值&#xff0c;并删除它。 找到 nums 中的最大值&#xff0c;并删除它。 计算删除两数的平均值。 两数 a 和 b 的 平均值…

[操作系统笔记]连续分配管理方式

内容系听课复习所做笔记&#xff0c;图例多来自课程截图 连续分配管理方式 连续分配&#xff1a;指为用户进程分配的必须是一个连续的内存空间 相应地&#xff0c;非连续分配可以是离散的 对于固定分区分配&#xff0c;需要有一个分区说明表&#xff0c;类似下表&#xff1a; …

【jmeter录制浏览器上特定的单个请求】

目录准备工作jmeter代理设置设置postman代理复制浏览器是特定的url背景&#xff1a;想要对浏览器某一个请求做测试&#xff0c;直接手动输入到jmeter不切实际&#xff0c;一般是使用jmeter代理的方式录制下来&#xff0c;但会有个问题&#xff0c;一般浏览器加载许多其他请求&a…

在虚拟机中安装Linux操作系统详细步骤

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起探讨和分享Linux C/C/Python/Shell编程、机器人技术、机器学习、机器视觉、嵌入式AI相关领域的知识和技术。 在虚拟机中安装Linux操作系统详细步骤专栏&#xff1a;《Linux从小白到大神》| 系统学习Linux开发、VI…

达梦数据库表空间误删恢复实操

达梦数据库表空间误删恢复实操1.表空间失效文件检查2.表空间失效文件恢复准备3.表空间失效文件恢复4.表空间失效文件恢复实操1.表空间失效文件检查 表空间恢复失效文件的检查。 语法格式 SP_FILE_SYS_CHECK ();语句功能 在 LINUX 操作系统下&#xff0c;检查是否有数据文件被…

一个已经存在10年,却被严重低估的 Python 库

今天介绍的是一个已经存在十年&#xff0c;但是依旧不红的库 decorator&#xff0c;好像很少有人知道他的存在一样。 这个库可以帮你做什么呢 &#xff1f; 其实很简单&#xff0c;就是可以帮你更方便地写python装饰器代码&#xff0c;更重要的是&#xff0c;它让 Python 中被…

代码随想录刷题Day52 | 300. 最长递增子序列 | 674. 最长连续递增序列 | 718. 最长重复子数组

代码随想录刷题Day52 | 300. 最长递增子序列 | 674. 最长连续递增序列 | 718. 最长重复子数组 300. 最长递增子序列 题目&#xff1a; 给你一个整数数组 nums &#xff0c;找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列&#xff0c;删除&#xff08;或…

2022年NPDP新版教材知识集锦--【第四章节】(6)

《产品经理认证(NPDP)知识体系指南(第2版)》已于2022年4月正式上架发行&#xff0c;新版教材自2022年11月NPDP考试起使用。将新版NPDP教材中的相关知识点进行了整理汇总&#xff0c;包括详细设计与规格阶段相关内容&#xff0c;快来看看吧。 【制造与装配阶段】(全部获取文末) …

SAP-ABAP-企业微信:ZCSM37-后台JOB异常检查主动推送企业微信群

场景&#xff1a;异常JOB主动推送企业微信群 &#xff08;企业微信机器人可百度创建&#xff0c;注意群不能有企业外的人员&#xff0c;否则接口无效&#xff09; 事务代码&#xff1a;ZSM37_CHECK程序名称&#xff1a;ZSM37_CHECK程序目的&#xff1a; ZCSM37-后台JOB异常检…

Java+JSP+MySQL基于SSM的物流公司物流订单管理系统-计算机毕业设计

项目介绍 随着我国经济的高速增长&#xff0c;物流快递的数量也在不断的增加&#xff0c;同时面临的就是如何更加方便快捷和高效的管理物流订单的问题&#xff0c;传统模式的物流订单管理模式明显已经不能够满足当下的需求&#xff0c;于是我们提出了基于B/S的贴心物流公司物流…

Redis未授权漏洞利用

1、背景介绍 近期公司内部安装主机安全组件&#xff0c;检测出一些安全漏洞&#xff0c;其中就有利用redis未授权漏洞进行攻击。 2、攻击原理 正常redis默认情况下&#xff0c;会绑定在0.0.0.0:6379&#xff0c;如果没有限制来源IP并且甚至没有密码&#xff0c;那么就会导致…

举个栗子~Minitab 技巧(5):掌握常用快捷键,提高统计分析效率

在日常使用 Minitab 时&#xff0c;大部分小伙伴的习惯是使用鼠标进行点击和拖拽等操作。然而&#xff0c;在使用频率很高的情况下&#xff0c;这种方式会带来很多重复且低效的劳动。 其实&#xff0c;Minitab 软件内置了许多快捷键&#xff0c;可以快速实现新建、打开、保存、…

虹科分析 | 终端安全 | 移动目标防御是“变革性”技术——GARTNER

使用前Gartner连续第二年将移动目标防御&#xff08;MTD&#xff09;作为特色技术&#xff0c;并将Morphisec作为该技术的样本供应商&#xff0c;在其报告《新兴技术影响雷达&#xff1a;安全》中。作者将MTD定义为“…一种技术趋势&#xff0c;其中动态或静态排列变形、转换或…

sentinel中流控规则 并发线程数的实战理解

先看下官网文档关于并发线程数的解释&#xff1a;链接地址 public class FlowThreadDemo {private static AtomicInteger pass new AtomicInteger();private static AtomicInteger block new AtomicInteger();private static AtomicInteger total new AtomicInteger();priva…

linux_mysql安装教程带安装包(亲测有效)

文章目录1.检查当前系统是否安装mysql2.上传mysql安装包/opt/software目录下3.解压安装包4.在安装目录下执行rpm安装5.删除/etc/my.cnf文件中datadir指向的目录下所有内容&#xff0c;6.初始化数据库7.查看临时生成的root用户密码8.启动mysql服务9.登陆mysql数据库10.修改root用…

Fiddler导出JMeter脚本插件原理

目录 一、Fiddler导出JMeter脚本插件原理 二、Fiddler导出JMeter脚本插件的基本使用 结语 一、Fiddler导出JMeter脚本插件原理 既然JMeter本质上是一个xml文档&#xff0c;Fiddler可以抓取HTTP请求包&#xff0c;插件的基本原理就是Fiddler抓取HTTP请求包将HTTP请求信息通过…