可视化图解算法:反转链表

1. 题目

描述

给定一个单链表的头结点pHead(该头节点是有值的,比如在下图,它的val是1),长度为n,反转该链表后,返回新链表的表头。

数据范围: 0<≤n≤1000

要求:空间复杂度 O(1) ,时间复杂度 O(n)。

如当输入链表{1,2,3}时,

经反转后,原链表变为{3,2,1},所以对应的输出为{3,2,1}。

以上转换过程如下图所示:

示例1

输入:

  {1,2,3}

返回值:

   {3,2,1}

示例2

输入:

  {}

返回值:

  {}

说明:

  空链表则输出空                 

2. 解题思路

假如说这是我们的链表,结构如下图所示:

第一步:定义3个指针变量,pre(序节点)、cur(当前操作的节点)和nxt(当前操作的下一个节点),结构如下图所示:

第二步:通过更改刚刚定义的3个指针变量反转链表节点。

  • 更改pre的指针域(next)指向:

               

    • 更改cur的指针域(next)指向:

      首先更改cur的指针域(next)指向,让它指向pre;之后再移动pre到cur除,最后移动cur到nxt处。

               

         这时,已经完成了链表的第一个和第二节点的反转。

      第三步:重复第二步的操作,直到链表的所有节点反转完成。

      如果cur指针变量指向的节点为Null时,就说明所有节点都完成了反转,循环退出,因此反转链表循环的条件:cur!=NUll。

      最后返回反转之后的头结点,头结点就是pre所指向的内容。

      如果文字描述的不太清楚,你可以参考视频的详细讲解。

      • Python版本:数据结构笔试面试算法-Python语言版_哔哩哔哩_bilibili数据结构笔试面试算法-Python语言版,bilibili课堂,哔哩哔哩课堂,哔哩哔哩,Bilibili,B站,弹幕https://www.bilibili.com/cheese/play/ep1370257

      • Java版本:数据结构笔试面试算法-Java语言版_哔哩哔哩_bilibili数据结构笔试面试算法-Java语言版,bilibili课堂,哔哩哔哩课堂,哔哩哔哩,Bilibili,B站,弹幕https://www.bilibili.com/cheese/play/ep1366713

      • Golang版本:数据结构笔试面试算法-Go语言版_哔哩哔哩_bilibili数据结构笔试面试算法-Go语言版,bilibili课堂,哔哩哔哩课堂,哔哩哔哩,Bilibili,B站,弹幕https://www.bilibili.com/cheese/play/ep1364390

      3. 编码实现

      3.1 Python编码实现

      class ListNode:
          def __init__(self, x):
              self.val = x  # 链表的数值域
              self.next = None  # 链表的指针域
      
      
      # 从链表节点尾部添加节点
      def insert_node(node, value):
          if node is None:
              print("node is None")
              return
          # 创建一个新节点
          new_node = ListNode(value)
          cur = node
          # 找到链表的末尾节点
          while cur.next is not None:
              cur = cur.next
          # 末尾节点的next指针域连接新节点
          cur.next = new_node
      
      
      # 打印链表(从链表头结点开始打印链表的值)
      def print_node(node):
          cur = node
          # 遍历每一个节点
          while cur is not None:
              print(cur.val, end="\t")
              cur = cur.next  # 更改指针变量的指向
          print()
      
      #
      #
      # @param head ListNode类
      # @return ListNode类
      #
      class Solution:
          def ReverseList(self, pHead: ListNode) -> ListNode:
              if pHead is None:
                  return pHead  # 节点为空,直接返回
              pre = None  # (操作的)前序节点
              cur = pHead  # (操作的)当前节点
              nxt = pHead  # (操作的)下一个节点
              while cur is not None:
                  nxt = cur.next  # 移动nxt指针
                  cur.next = pre  # 更改当前节点(cur)指针域的指向
                  pre = cur  # 移动pre指针
                  cur = nxt  # 移动cur指针
              return pre  # 返回反转之后的头结点
      
      
      if __name__ == '__main__':
          root = ListNode(1)
          insert_node(root, 2)
          insert_node(root, 3)
          insert_node(root, 4)
          insert_node(root, 5)
          print_node(root)
      
          s = Solution()
          node = s.ReverseList(root)
          print_node(node)

      3.2 Java编码实现

      package LL01;
      
      
      public class Main {
          //定义链表节点
          static class ListNode {
              private int val;  //链表的数值域
              private ListNode next; //链表的指针域
      
              public ListNode(int data) {
                  this.val = data;
                  this.next = null;
              }
          }
      
          //添加链表节点
          private static void insertNode(ListNode node, int data) {
              if (node == null) {
                  return;
              }
              //创建一个新节点
              ListNode newNode = new ListNode(data);
              ListNode cur = node;
              //找到链表的末尾节点
              while (cur.next != null) {
                  cur = cur.next;
              }
              //末尾节点的next指针域连接新节点
              cur.next = newNode;
          }
      
          //打印链表(从头节点开始打印链表的每一个节点)
          private static void printNode(ListNode node) {
              ListNode cur = node;
              //遍历每一个节点
              while (cur != null) {
                  System.out.print(cur.val + "\t");
                  cur = cur.next; //更改指针变量的指向
              }
              System.out.println();
          }
      
          public static  class Solution {
              /**
               * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
               *
               * @param pHead ListNode类
               * @return ListNode类
               */
              public ListNode ReverseList(ListNode pHead) {
                  // write code here
                  if (pHead == null) {
                      return pHead;
                  }
                  ListNode pre = null;//前序节点
                  ListNode cur = pHead; //(操作的)当前节点
                  ListNode nxt = pHead; //下一个节点
                  while (cur != null) {
                      nxt = cur.next;//移动nxt指针
                      cur.next = pre;// 更改当前节点(cur)指针域的指向
                      pre = cur;//移动pre指针
                      cur = nxt;//移动cur指针
                  }
                  return pre;//返回反转之后的头结点
              }
          }
      
          public static void main(String[] args) {
      
              ListNode root = new ListNode(1);
              insertNode(root, 2);
              insertNode(root, 3);
              insertNode(root, 4);
              insertNode(root, 5);
              printNode(root);
      
              Solution solution = new Solution();
              ListNode node = solution.ReverseList(root);
              printNode(node);
          }
      }

      3.3 Golang编码实现

      package main
      
      import "fmt"
      
      // ListNode 定义链表节点
      type ListNode struct {
      	Val  int       //链表的数值域
      	Next *ListNode //链表的指针域
      }
      
      func main() {
      	root := &ListNode{
      		Val:  1,
      		Next: nil,
      	}
      	root.Insert(2)
      	root.Insert(3)
      	root.Insert(4)
      	root.Insert(5)
      	root.Print()
      	node := ReverseList(root)
      	node.Print()
      }
      func ReverseList(pHead *ListNode) *ListNode {
      	if pHead == nil {
      		return pHead //节点为空,直接返回
      	}
      	var pre *ListNode //(操作的)前序节点
      	cur := pHead      //(操作的)当前节点
      	nxt := pHead      //(操作的)下一个节点
      	for cur != nil {
      		nxt = cur.Next //移动nxt指针
      		cur.Next = pre // 更改当前节点(cur)指针域的指向
      		pre = cur      //移动pre指针
      		cur = nxt      //移动cur指针
      	}
      	return pre //返回反转之后的头结点
      }
      
      // Insert 从链表节点尾部添加节点
      func (ln *ListNode) Insert(val int) {
      	if ln == nil {
      		return
      	}
      	//创建一个新节点
      	newNode := &ListNode{Val: val}
      	cur := ln
      	//找到链表的末尾节点
      	for cur.Next != nil {
      		cur = cur.Next
      	}
      	//末尾节点的next指针域连接新节点
      	cur.Next = newNode
      }
      
      // Print 从链表头结点开始打印链表的值
      func (ln *ListNode) Print() {
      	if ln == nil {
      		return
      	}
      	cur := ln
      	//遍历每一个节点
      	for cur != nil {
      		fmt.Print(cur.Val, "\t")
      		cur = cur.Next //更改指针变量的指向
      	}
      	fmt.Println()
      }
      

      如果上面的代码理解的不是很清楚,你可以参考视频的详细讲解。

      • Python编码:哔哩哔哩_bilibilihttps://www.bilibili.com/cheese/play/ep1370257

      • Java编码:哔哩哔哩_bilibilihttps://www.bilibili.com/cheese/play/ep1366713

      • Golang编码:数据结构笔试面试算法-Go语言版_哔哩哔哩_bilibili数据结构笔试面试算法-Go语言版,bilibili课堂,哔哩哔哩课堂,哔哩哔哩,Bilibili,B站,弹幕https://www.bilibili.com/cheese/play/ep1364390

      4.小结

      本题的难点在于定义出3个指针变量,pre(序节点)、cur(当前操作的节点)和nxt(当前操作的下一个节点),并在初始化的时候明确指向,之后就可以更改cur的指针域(nxt)、移动pre、cur。由于链表节点有多个,操作方法一样,因此采用循环的方法。当cur指向Null时,说明链表的所有节点都完成了反转。

      更多算法视频讲解,你可以从以下地址找到:

      • Python编码实现:哔哩哔哩_bilibilihttps://www.bilibili.com/cheese/play/ep1509965

      • Java编码实现:哔哩哔哩_bilibilihttps://www.bilibili.com/cheese/play/ep1510007

      • Golang编码实现:数据结构笔试面试算法-Go语言版_哔哩哔哩_bilibili数据结构笔试面试算法-Go语言版,bilibili课堂,哔哩哔哩课堂,哔哩哔哩,Bilibili,B站,弹幕https://www.bilibili.com/cheese/play/ep1509945

      对于链表的相关操作,我们总结了一套【可视化+图解】方法,依据此方法来解决链表相关问题,链表操作变得易于理解,写出来的代码可读性高也不容易出错。具体也可以参考视频详细讲解。

      今日佳句:众里寻他千百度。蓦然回首,那人却在,灯火阑珊处。

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

      如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

      相关文章

      P8685 [蓝桥杯 2019 省 A] 外卖店优先级--优先队列“数组”!!!!!

      P8685 [蓝桥杯 2019 省 A] 外卖店优先级 题目 解析优先队列如何判断是否使用优先队列&#xff1f;省略规则优先队列常用操作大顶堆 vs 小顶堆定义队列h队列数组 代码 题目 解析 每个外卖店会在不同的时间点收到订单&#xff0c;我们可以看见测试用例的时间顺序是不同的&#x…

      使用苹果M芯片打包Docker Image无法在amd64环境下运行

      问题所在 使用苹果M芯片打包Docker Image无法在amd64环境下运行&#xff0c;因为arm环境下打包docker默认打包为arm格式&#xff0c;可以使用以下命令查看&#xff1a; docker inspect <ImageID>找到Architecture&#xff0c;可以发现 解决方法 在docker-compose.ym…

      低代码开发直聘管理系统

      低代码 DeepSeek 组合的方式开发直聘管理系统&#xff0c;兼职是开挂的存在。整个管理后台系统 小程序端接口的输出&#xff0c;只花了两个星期不到。 一、技术栈 后端&#xff1a;SpringBoot mybatis MySQL Redis 前端&#xff1a;Vue elementui 二、整体效果 三、表结…

      MySQL的安装及配置

      一.以安装包方式下载 1.进入MySQL官网&#xff0c;下载安装包 官网链接&#xff1a;https://downloads.mysql.com/archives/installer/ 2.安装MySQL 二.压缩包方式下载 下载位置&#xff1a;mysql下载位置 解压缩后位置&#xff1a;D:\mysql-8.0.15-winx64 在主目录下复制…

      CI/CD—Jenkins配置一次完整的jar自动化发布流程

      背景&#xff1a; 实现设想&#xff1a; 要创建自动化发布&#xff0c;需要准备一台测试服务器提前安装好java运行所需的环境&#xff0c;JDK版本最好和Windows开发机器上的版本一致&#xff0c;在Jenkins上配置将构建好的jar上传到测试服务器上&#xff0c;测试服务器自动启动…

      C++蓝桥杯皮亚诺曲线距离求解

      C蓝桥杯皮亚诺曲线距离求解 一、题目概述二、解题分析2.1解题思路2.2k值范围限制 三、实现代码四、代码测试4.1蓝桥杯测试平台4.2直接传入原始输入的k值4.3限制k值大小4.4pow函数求整数高次幂存在误差4.5满分代码 附录error: ‘long long int y1’ redeclared as different kin…

      开源!速度100Kb/s的有线和无线双模ESP32S3芯片的DAP-Link调试器

      开源&#xff01;速度100Kb/s的有线和无线双模ESP32S3芯片的DAP-Link调试器 目录 开源&#xff01;速度100Kb/s的有线和无线双模ESP32S3芯片的DAP-Link调试器本项目未经授权&#xff0c;禁止商用&#xff01;本项目未经授权&#xff0c;禁止商用&#xff01;本项目未经授权&…

      简记_硬件系统设计之需求分析要点

      目录 一、 功能需求 二、 整体性能需求 三、 用户接口需求 四、 功耗需求 五、 成本需求 六、 IP和NEMA防护等级需求 七、 认证需求 功能需求 供电方式及防护 供电方式&#xff1a;市电供电、外置直流稳压电源供电、电池供电、PoE&#xff08;Power Over Ether…

      python连接deepseek api实例

      步骤一&#xff1a;安装必要的库&#xff0c;如openai&#xff1b; 步骤二&#xff1a;deepseek平台申请api&#xff0c;并充值&#xff08;可先充10元&#xff09;&#xff0c;费用大概一个查询2分钱的样子&#xff1b; 步骤三&#xff1a;设置环境变量&#xff1a;DEEPSEEK…

      抽象类与普通类

      抽象类和普通类的区别&#xff1a; 抽象类其实就是普通类和接口&#xff08;完全抽象&#xff09;之间的设计工具。通过抽象类&#xff0c;可以更灵活地构建可扩展、可维护的类层次结构。抽象类的核心价值在于平衡代码复用和规范约束。 示例&#xff1a;

      免费生成可下载ppt

      1.天工AI 免费的&#xff0c;模版很少&#xff0c;效果不是很好&#xff1b; 2.Kimi 免费的&#xff0c;模版不多&#xff0c;效果还可以&#xff1b;

      【解决哈希冲突】

      哈希冲突 如果两个不同的 key 通过哈希函数得到了相同的索引&#xff0c;这种情况就叫做「哈希冲突」。 哈希冲突不可能避免&#xff0c;只能在算法层面妥善处理出现哈希冲突的情况。 哈希冲突是一定会出现的&#xff0c;因为这个 hash 函数相当于是把一个无穷大的空间映射到…

      基于LabVIEW的脚本化子VI动态生成

      该示例展示了一种利用LabVIEW VI脚本&#xff08;VI Scripting&#xff09;技术&#xff0c;通过程序化方式动态生成并替换子VI的解决方案。核心逻辑为&#xff1a;基于预定义的模板VI&#xff0c;根据用户选择的数学操作&#xff08;加法或乘法&#xff09;&#xff0c;自动生…

      谷歌AI最新发布的可微分逻辑元胞自动机(DiffLogic CA)

      每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

      如何使用Postman,通过Mock的方式测试我们的API

      这篇文章将教会大家如何利用 postman&#xff0c;通过 Mock 的方式测试我们的 API。 什么是 Mock Mock 是一项特殊的测试技巧&#xff0c;可以在没有依赖项的情况下进行单元测试。通常情况下&#xff0c;Mock 与其他方法的主要区别就是&#xff0c;用于取代代码依赖项的模拟对…

      pytest基础知识

      pytest知识了解 pytest的基础知识了解&#xff1a;Python测试框架之pytest详解_lovedingd的博客-CSDN博客_pytest框架 (包含设置断点&#xff0c;pdb&#xff0c;获取最慢的10个用例的执行耗时) pytest-pytest.main()运行测试用例&#xff0c;pytest参数&#xff1a; pytest-…

      LM Studio 替换源的方式解决huggingface.co无法访问的问题

      安装软件完成之后&#xff0c;不要打开&#xff0c;打开了就直接关闭 在安装目录下&#xff0c;比如我安装在E:\Program Files\LM Studio 下面三个文件中的huggingface.co全部替换为hf-mirror.com然后再打开即可。 E:\Program Files\LM Studio\resources\app\.webpack\rende…

      【含文档+PPT+源码】基于微信小程序的乡村振兴民宿管理系统

      项目介绍 本课程演示的是一款基于微信小程序的乡村振兴民宿管理系统&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的 Java 学习者。 1.包含&#xff1a;项目源码、项目文档、数据库脚本、软件工具等所有资料 2.带你从零开始部署运行本套系统 3.该…

      五、OpenGL中Shader与C++数据传输

      文章目录 一、概述二、Shader 代码文件的基本格式三、Shader的向量语法介绍四、Shader之间的数据传输五、Shader与C的数据传输uniform六、完整示例 一、概述 在 OpenGL 中&#xff0c;Shader&#xff08;着色器&#xff09;使用 GLSL&#xff08;OpenGL Shading Language&…

      docker不停机部署

      背景 最近做大疆项目时&#xff0c;后台更新部署时&#xff0c;机场和无人机就会掉线。设备自动重连注册时间比较长&#xff0c;应用长时间不可用。所以需要灰色发布服务。docker-compose的swarm模式可解决此问题。 服务构建脚本Dockerfile # 使用官方Java基础镜像&#xff…