当前位置: 首页 > news >正文

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

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

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

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

      相关文章:

    • 《面向长尾分布的甲骨文识别算法设计与实现 》开题报告
    • 力扣hot100二刷——哈希、双指针、滑动窗口
    • C/C++中使用CopyFile、CopyFileEx原理、用法、区别及分别在哪些场景使用
    • 【gcc编译以及Makefile与GDB调试】
    • python LLM工具包
    • JavaScript数据类型和内存空间
    • 20-智慧社区物业管理平台
    • Java【多线程】(3)单例模式与线程安全
    • 大模型如何从开始到编译出Engine
    • [免费]微信小程序(图书馆)自习室座位预约管理系统(SpringBoot后端+Vue管理端)(高级版)【论文+源码+SQL脚本】
    • 一个简化版的进程内通信库实现
    • 深入理解Java中的static关键字及其内存原理
    • 《云原生技术:DeepSeek分布式推理的效能倍增器》
    • Git系列之git checkout
    • 发起请求的步骤
    • Spring Boot整合WebSocket
    • 基于深度学习的中文文本情感分析系统
    • EasyTwin全新体验 | 春启新章,智焕新生
    • 隧道定向号角喇叭为隧道安全保驾护航
    • Microsof Visual Studio Code 安装教程(中文设置)
    • 61岁云浮市律师协会副会长谭炳光因突发疾病逝世
    • 南宁一学校发生伤害案件,警方通报:嫌疑人死亡,2人受伤
    • 曾犯强奸罪教师出狱后办教培机构?柳州鱼峰区教育局回应
    • 崔登荣任国家游泳队总教练
    • 印度军方否认S-400防空系统被摧毁
    • 巴总理召开国家指挥当局紧急会议