链表题目总结 -- 递归

news2024/9/20 20:22:33

目录

  • 一. 递归反转整个链表
    • 1. 思路简述
    • 2. 代码
    • 3. 总结
  • 二. 反转链表前 N 个节点
    • 1. 思路简述
    • 2. 代码
    • 3. 总结
  • 三、反转链表的一部分
    • 1. 思路简述
    • 2. 代码
    • 3.总结
  • 四、反转链表后N个节点
    • 1. 思路简述
    • 2. 代码
    • 3.总结

一. 递归反转整个链表

  • 题目链接:https://leetcode.cn/problems/reverse-linked-list/

1. 思路简述

  • 所谓递归,就像那句歌词一样“一层一层剥开我的心”,我们从第一个节点一直向下探索,发现节点5。现在想:如果是单个节点,那反转链表其实就相当于自身本身,也就是不用动了。这里考虑一个临界情况,如果传进的参数(head指针)是null,那也不用动了,直接返回其本身就可以。
  • 来到倒数第二层,也就是节点4,现在情况变成了节点有2个的链表,现在需要反转,那么我们只需要将中间的指针做一个反转就好了,而当前传进来的指针(head),其实是节点4的head指针,那么就有head.next.next = head;,最后将节点4的后继赋值为空(head.next = null),这表示这一阶段(有2个节点的链表已经反转完成。如果链表只有两个节点,直接输出就可以。)
  • 重复上面步骤,直到最后整个链表都反转了
    在这里插入图片描述

2. 代码

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {                       
    public ListNode reverseList(ListNode head) {
        //从后向前,一点点的进行反转
        //先分析特殊情况,链表有一个节点或者没有节点,直接返回头结点
        if(head == null || head.next == null)
            return head;
        else{
        	//last为反转链表之后的头指针
            ListNode last = reverseList(head.next);
            head.next.next = head;
            head.next = null;
            return last;
        }
    }
}

3. 总结

  • 时间复杂度:o(n)
  • 空间复杂度:o(n),需要用栈
  • 第一次做的时候,还以为是逆向输出,整了半天,搞错了。
  • 对递归的边界条件掌握的还是不好,像head == null这一块,博主当时就没想到与head.next进行合并。
  • head.next = null;一定要注意,否则,会出现成环的现象

二. 反转链表前 N 个节点

  • 题目链接:没有链接,给一个函数名:public static ListNode reverseN(ListNode head,int n);,自己去练吧。

1. 思路简述

  • 本质和反转链表差不多,只是在边界值的地方需要注意,

2. 代码

		//存放需要逆转链表的后继第一个节点
    	public static ListNode successor = null;
    	
        public static ListNode reverseN(ListNode head,int n){
            //逆转前n个节点
            if (n == 1) {
                successor = head.next;
                return head;
            }
            //递归,将下一个节点放进去
            ListNode last = reverseN(head.next, n - 1);
            head.next.next = head;
            head.next = successor;

            return last;
        }

3. 总结

  • 也就是反转链表,只是每次反转完,head后面要接后继节点(后面的一段不需要反转的链表),就变了这一点。
  • 时间复杂度:o(n)
  • 空间复杂度:o(n),需要用栈

三、反转链表的一部分

  • 题目链接:没有链接,给一个函数名:public static ListNode reverseBetween(ListNode head, int m, int n);,自己去练吧。

1. 思路简述

  • 将问题转换成反转前n个节点的问题。

2. 代码

	//存放需要逆转链表的后继第一个节点
   	public static ListNode successor = null;
   	
       public static ListNode reverseN(ListNode head,int n){
           //逆转前n个节点
           if (n == 1) {
               successor = head.next;
               return head;
           }
           //递归,将下一个节点放进去
           ListNode last = reverseN(head.next, n - 1);
           head.next.next = head;
           head.next = successor;

           return last;
       }
       
		ListNode reverseBetween(ListNode head, int m, int n) {
	  	    // 当m为1的时候,装换成了反转前面几个节点的链表的问题
		    if (m == 1) {
		        return reverseN(head, n);
		    }
		    // 将前面不需要反转的链表和后面反转过的链表接在一起
		    head.next = reverseBetween(head.next, m - 1, n - 1);
		    
	    	return head;
	   }

3.总结

  • head.next = reverseBetween(head.next, m - 1, n - 1); 为什么是head.next呢,看边界情况,m = 1时,返回的是后面已经反转过的链表,也就是说前面的链表压根不需要反转,只要把它们拼接在一起就行了。
  • 再说为什么是m - 1的问题,每递归一次,新链表就会从前面缩短一节,那么对于新链表来说,就是从第m-1个节点开始反转,到第n - 1个节点结束反转。这里的关键是链表从头开始缩短了,所以,m - 1 和 n - 1都要存在。

四、反转链表后N个节点

  • 题目链接:没有链接,给一个函数名:public static ListNode reverseN(ListNode head,int n);,自己去练吧。

1. 思路简述

  • 转换成反转链表的问题

2. 代码

    public ListNode reverseList(ListNode head) {
        //从后向前,一点点的进行反转
        //先分析特殊情况,链表有一个节点或者没有节点,直接返回头结点
        if(head == null || head.next == null)
            return head;
        else{
        	//last为反转链表之后的头指针
            ListNode last = reverseList(head.next);
            head.next.next = head;
            head.next = null;
            return last;
        }
    }
    
    public static ListNode reverseP(ListNode head, int m){
        //转换成反转链表的问题
        if(m == 1){
            return reverseList(head);
        }
        head.next = reverseP(head.next, m - 1);

        return head;
    }

3.总结

  • 就是上面一题的简化版,不多做赘述

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

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

相关文章

部署智能合约到公链

🍁博主简介: 🏅云计算领域优质创作者 🏅2022年CSDN新星计划python赛道第一名 🏅2022年CSDN原力计划优质作者 🏅阿里云ACE认证高级工程师 🏅阿里云开发者社区专…

【面试】生命周期详情解释及案例

目录 1.什么是生命周期 2.生命周期函数 3.vue2中生命周期的函数 4.生命周期的阶段 5.生命周期图示 第一个阶段:组件创建阶段 第二个阶段:编译HTML模板并渲染到浏览器中 第三阶段:组件更新阶段 第四阶段:组件销毁阶段 1.什…

【数据结构】基础:图的基本概念与实现(附C++源代码)

【数据结构】基础:图的基本概念与实现(附C源代码) 摘要:将会在数据结构专题中开展关于图论的内容介绍,其中包括四部分,分别为图的概念与实现、图的遍历、图的最小生成树以及图的最短路径问题。本文将介绍图…

遗传算法(Genetic Algorithm,GA)实现数据排序,python

遗传算法(Genetic Algorithm,GA)实现数据排序,python 遗传算法是一种比较广泛、通用的算法体系,为了说明遗传算法的原理和实现,现在用GA解决一个计算机科学最基本、最古老的问题:排序问题。 需要特别说明的是,遗传算…

【GPLT 三阶题目集】L3-016 二叉搜索树的结构

二叉搜索树或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;它的左、右子树也分…

代码随想录LeetCode | 单调栈问题

前沿:撰写博客的目的是为了再刷时回顾和进一步完善,其次才是以教为学,所以如果有些博客写的较简陋,是为了保持进度不得已而为之,还请大家多多见谅。 预:看到题目后的思路和实现的代码。 见:参考…

两种特征提取方法与深度学习方法对比的小型金属物体分类分析研究

本文讨论了用于对包括螺丝、螺母、钥匙和硬币在内的小型金属物体进行分类的两种特征提取方法的效率:定向梯度直方图 (HOG) 和局部二进制模式 (LBP)。首先提取标记图像的所需特征并以特征矩阵的形式保存。使用三种不同的分类方法(非参数 K 最近邻算法、支…

云计算|OpenStack|社区版OpenStack(实务操作---cloud-init的使用)

前言: 接上一篇文章:https://zskjohn.blog.csdn.net/article/details/128931042 我们可以从官方获取到现成的镜像,例如,从Ubuntu 18.04 LTS (Bionic Beaver) Daily Build [20230210]官方下载的bionic-server-cloudimg-amd64.img…

春招Leetcode刷题日记-D2-贪心算法-区间问题

D2-贪心算法-区间问题力扣435. 无重叠区间思路代码力扣435. 无重叠区间 题目链接:435. 无重叠区间 思路 1、贪心策略: 1、题目中,给了若干个区间,现在,我想留下尽可能多的,不重叠的区间 2、考虑&#…

Git配置多仓库账户密码

前言说明: 由于我们在工作中可能会遇到公司是用的gitlab仓库,代码下载需要github仓库,自己的项目需要gitee仓库,如何在同一台电电脑配置多个仓库账户密码就尤为重要。 (一) 配置流程 这里是在windows电脑上配置多仓库以github为例…

使用Spring框架的好处是什么

使用Spring框架的好处是什么? 1、轻量:Spring 是轻量的,基本的版本大约2MB。 2、控制反转:Spring通过控制反转实现了松散耦合,对象们给出它们的依赖,而不是创建或查找依赖的对象们。 3、面向切面的编程(AOP…

JCIM|Chemistry42:一个人工智能驱动的分子设计和优化平台

题目:Chemistry42: An AI-Driven Platform for Molecular Design and Optimization 文献来源:https://doi.org/10.1021/acs.jcim.2c01191 代码:https://insilico.com/pipeline (平台网址) 1.背景介绍 Chemistry42是Insilico Medicine提出…

Git_合并多次提交记录

Git_合并多次提交记录 前言:使用git rebase将多条提交记录合并成一条 应用场景:公司代码分支在master上,张三接到一个开发任务,需要在master上开发一个新功能,首先张三不能直接使用master分支进行开发,因为…

论文阅读:GeoAug: Data Augmentation for Few-Shot NeRF with Geometry Constrain

中文标题:使用几何约束增强小样本神经辐射场 提出的问题 NeRF尽管简介有效,但是往往不能收敛到正确的几何结构。这个问题在小样本学习中尤为明显,往往在没有足够训练数据的情况下,很难使得MLP网络学习到正确的几何的隐表示&#…

Solon Java Framework 2.1.2 发布。简单!高效!国产!

Solon 是一个高效的 Java 应用开发框架:更快、更小、更简单。它不是 Spring,没有用 Servlet,也无关 JavaEE;它也是一个新兴独立的开放生态。主框架仅 0.1 MB。 150来个生态插件,覆盖各种不同的应用开发场景&#xff1…

Linux Capabilities 入门

目录 Linux capabilities 是什么? capabilities 的赋予和继承 线程的 capabilities Permitted Effective Inheritable Bounding Ambient 文件的 capabilities Permitted Inheritable Effective 运行 execve() 后 capabilities 的变化 案例 Linux capab…

黑马】后台管理183-

一、添加时间线组件时间线组件在element2.6.0的版本中才可以找到项目中用到的插件早于时间线插件发布的,所以需要用到素材中的,timeline 和timeline-item复制到\code\shop-hou\src\plugins\1,在element.js中导入timeline等组件import Timeline from ./ti…

20230213在AIO-3568J开发板在原厂Android12下跑通ap6275s

20230213在AIO-3568J开发板在原厂Android12下跑通ap6275s 2023/2/13 8:59 一、从AIO-3568的Android11的kernel中抠出来AP6275S的驱动: 1、 Z:\android12-rk3588-new\kernel-4.19\arch\arm64\configs\rockchip_defconfig # CONFIG_WLAN_VENDOR_QUANTENNA is not set …

电路中的过压(OVP)过流(OCP)保护电路

电路中的过压(OVP)过流(OCP)保护电路 我们在学习电路设计的过程中,总会发现电路在过压或者过流时遭到不可逆的损坏, 下面分享几例过压过流保护电路, 希望对朋友们有所帮助, 个人能力有限, 如有不当之处还请多多指教: 例 1:OVP(过压保护) 1).当VCC_IN小于28V时&…

spring(三)-----------什么是beanDefinition?

上篇我们以mybatis如何注入mapper对象为引,发现mybatis使用了FactoryBean(动态代理)动态注册beanDefinition 的方式实现了对多个bean进行注入。 这篇我们延续上篇的问题,什么是beanDefinition?动态注入beanDefinition…