掌握反转链表的艺术:LeetCode 206 深入解析与优化 - 双指针与递归方法精讲

LeetCode.206反转链表

  • 1.问题描述
  • 2.解题思路
  • 3.代码

1.问题描述

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

示例 1:

输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]

示例 2:

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

示例 3:

输入:head = []
输出:[]

提示:

  • 链表中节点的数目范围是 [0, 5000]
  • -5000 <= Node.val <= 5000

2.解题思路

如果再定义一个新的链表,实现链表元素的反转,其实这是对内存空间的浪费。其实只需要改变链表的next指针的指向,直接将链表反转 ,而不用重新定义一个新的链表,如图所示:

  1. 双指针法(双指针解其他题常见,点击链接跳转即可)

    • 定义一个cur指针,指向头结点;再定义一个pre指针,初始化为null。

    • 那我们目的是反转链表,也就是让当前头结点指向null,再将头结点的下一个节点,指向头节点。

    • 首先要把 cur->next 节点用tmp指针保存一下,也就是保存一下这个节点。为什么要保存一下这个节点呢,因为接下来要改变 cur->next 的指向了,将cur->next 指向pre ,此时已经反转了第一个节点了。

    • 接下来循环逻辑,不断移动pre和cur指针。

    • 最后,cur 指针已经指向了null,循环结束,链表也反转完毕了。 此时我们return pre指针就可以了,pre指针就指向了新的头结点。

    • 时间复杂度: O(n)

    • 空间复杂度: O(1)

  2. 递归

    与双指针法是一样的逻辑,同样是当cur为空的时候循环结束,不断将cur指向pre的过程。

    • 时间复杂度: O(n), 要递归处理链表的每个节点
    • 空间复杂度: O(n), 递归调用了 n 层栈空间

3.代码

C++:双指针

#include <iostream>
#include <vector>
using namespace std;

// 定义链表节点结构
struct ListNode {
	int val;        // 节点存储的值
	ListNode* next; // 指向下一个节点的指针
	ListNode(int x) : val(x), next(NULL) {} // 构造函数
};

class Solution {
	public:
		
		ListNode* reverseList(ListNode* head) {
			ListNode* cur = head; // 当前节点指针
			ListNode* pre = NULL; // 前一个节点指针
			ListNode* tmp;        // 临时节点指针

			while(cur) {
				tmp = cur->next;  // 保存一下 cur的下一个节点,因为接下来要改变cur->next
				cur->next = pre;  // 反转指针方向
				// 更新pre 和 cur指针
				pre = cur;        
				cur = tmp;        
			}
			return pre;          // 返回反转后的头节点
		}
};

// 根据一个整数数组创建链表
ListNode* createList(const vector<int>& nums) {
	ListNode* head = NULL; // 链表头指针
	ListNode* tail = NULL; // 链表尾指针

	for (int num : nums) {
		ListNode* newNode = new ListNode(num); // 创建新节点
		if (!head) {
			head = newNode; // 初始化头尾节点为第一个节点
			tail = newNode;
		} else {
			tail->next = newNode; // 在尾部添加新节点
			tail = newNode;       // 更新尾指针
		}
	}
	return head; // 返回链表头指针
}

// 打印链表中的元素
void printList(ListNode* head) {
	ListNode* cur = head; // 当前节点指针
	while(cur) {
		cout << cur->val << " "; // 打印当前节点值
		cur = cur->next;         // 移动到下一个节点
	}
	cout << endl; // 打印换行符
}

// 主函数
int main() {
	vector<int> nums; // 存储用户输入的整数数组
	int num;          // 用户输入的单个整数

	// 提示用户输入,以0结束
	cout << "Enter numbers for the list (0 to end): ";
	while (cin >> num && num != 0) {
		nums.push_back(num); // 将输入的数字添加到数组中
	}

	// 创建链表
	ListNode* head = createList(nums);

	// 打印反转前的链表
	cout << "Before reverse: ";
	printList(head);

	// 创建Solution类实例,并反转链表
	Solution sol;
	ListNode* newHead = sol.reverseList(head);

	// 打印反转后的链表
	cout << "After reverse: ";
	printList(newHead);

	return 0; // 程序正常结束
}

C++:递归

class Solution {
public:
    ListNode* reverse(ListNode* pre,ListNode* cur){
        if(cur == NULL) return pre;  //终止条件
        ListNode* temp = cur->next;
        cur->next = pre;
        // 可以和双指针法的代码进行对比,如下递归的写法,其实就是做了这两步
        // pre = cur;
        // cur = temp;
        return reverse(cur,temp);  //下一层递归,根据上面,把cur赋值给pre,把temp赋值给cur,所以reverse传入的参数,第一个为,cur,第二个为temp,就可以实现递归了
    }
    ListNode* reverseList(ListNode* head) {
        // 和双指针法初始化是一样的逻辑
        // ListNode* cur = head;
        // ListNode* pre = NULL;
        return reverse(NULL, head);
    }

};

python:双指针

class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next


class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        cur = head
        pre = None
        while cur:
            temp = cur.next  # 保存一下 cur 的下一个节点
            cur.next = pre  # 反转
            pre = cur  # 更新 pre 和 cur 指针
            cur = temp
        return pre


def createList(nums):
    head = None
    tail = None
    for num in nums:
        if not head:
            head = ListNode(num)
            tail = head
        else:
            tail.next = ListNode(num)
            tail = tail.next
    return head


def printList(head):
    cur = head
    while cur:
        print(cur.val, end=" ")
        cur = cur.next
    print()


# 主程序
if __name__ == "__main__":
    nums = list(map(int, input("Enter numbers for the list (separated by space): ").split()))
	
    head = createList(nums)
    print("Before reverse:")
    printList(head)

    sol = Solution()
    newHead = sol.reverseList(head)

    print("After reverse:")
    printList(newHead)

python: 递归

class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        return self.reverse(head, None)
    def reverse(self, cur: ListNode, pre: ListNode) -> ListNode:
        if cur == None:
            return pre
        temp = cur.next
        cur.next = pre
        return self.reverse(temp, cur)

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

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

相关文章

SpringBoot监控Redis事件通知

Redis的事件通知 Redis事件通过 Redis 的订阅与发布功能&#xff08;pub/sub&#xff09;来进行分发&#xff0c; 因此所有支持订阅与发布功能的客户端都可以在无须做任何修改的情况下&#xff0c; 使用键空间通知功能。 因为 Redis 目前的订阅与发布功能采取的是发送即忘&am…

oracle impdp 导入元数据表空间异常增大的解决办法

expdp导出的时候指定了contentsmetadata_only只导出元数据&#xff0c;但是在impdp导入到新库的时候&#xff0c;发现新库的表空间增长非常大&#xff0c;其实这个直接就可以想到&#xff0c;应该是大表的initial segment过大导致的 正常impdp&#xff0c;在执行创建表和索引的…

SocialFi 和 GameFi 的碰撞 — Socrates 构建新的 Web3 流量入口

伴随着比特币现货 ETF 即将通过 SEC 批准的消息&#xff0c;整个加密市场在11月份达到了熊市以来的新高峰。市场普遍上涨&#xff0c;新的玩法和项目不断涌出吸引了大量老用户回归以及新用户加入。加密市场经过长期的低迷&#xff0c;终于来到了牛市的起点&#xff01; 上一轮牛…

振南技术干货集:znFAT 硬刚日本的 FATFS 历险记(6)

注解目录 1、znFAT 的起源 1.1 源于论坛 &#xff08;那是一个论坛文化兴盛的年代。网友 DIY SDMP3 播放器激起了我的兴趣。&#xff09; 1.2 硬盘 MP3 推了我一把 &#xff08;“坤哥”的硬盘 MP3 播放器&#xff0c;让我深陷 FAT 文件系统不能自拔。&#xff09; 1.3 我…

正则表达式和awk

目录 一、正则表达式 1.正则表达式基本介绍 2.正则表达式分类 3.基本正则表达式分类 4.代表字符 5.表示次数 6.位置锚定 7.分组或其他 8.扩展正则表达式 二、awk 1.语法 2.选项 3.基础用法 4.内置变量 5.条件判断 6.数组 总结&#xff1a;本章主要介绍了正则表…

分享:身份证阅读器在ARM Linux系统调用libwlt2bmp.so解码库实现身份证头像解码

头像解码库&#xff1a;libwlt2bmp.so 照片文件名&#xff1a;photo.bmp 原始身份证相片数据&#xff1a;574C66007E00320000F........&#xff08;此处省略&#xff09; 调用身份证阅读器Linux开发包&#xff0c;然后调用libwlt2bmp.so解码库文件&#xff0c;传入身份证原始…

0基础学习VR全景平台篇第123篇:VR视频航拍补天 - PR软件教程

上课&#xff01;全体起立~ 大家好&#xff0c;欢迎观看蛙色官方系列全景摄影课程&#xff01; 嗨&#xff0c;大家好&#xff0c;今天我们来介绍【航拍VR视频补天】。之前已经教给了大家如何处理航拍图片的补天&#xff0c;肯定有很多小伙伴也在好奇&#xff0c;航拍的VR视频…

地图标注系统v0.10.1

微启地图标注系统 thinkphpuniapp前端&#xff0c;微信小程序已适配&#xff0c;近期更新抖音小程序和QQ小程序&#xff0c;后期上分销功能&#xff0c;标注系统用户粘性不算大&#xff0c;本着小程序用完即走的理念&#xff0c;暂时没打算适配安卓和iOS 主要功能 用户端&am…

移动安全威胁:今天和明天的危险

随着技术的发展&#xff0c;个人和公司的设备、数据和隐私所面临的威胁也在发生变化。在本文中&#xff0c;我们将仔细研究当今移动设备安全面临的主要威胁&#xff0c;并共同探讨不久的将来的前景。 但首先让我们从基础开始&#xff1a;如何对移动设备发起攻击&#xff1f; …

1.ORB-SLAM3中如何保存多地图、关键帧、地图点到二进制文件中

1 保存多地图 1.1 为什么保存(视觉)地图 因为我们要去做导航&#xff0c;导航需要先验地图。因此需要保存地图供导航使用&#xff0c;下面来为大家讲解如何保存多地图。 1.2 保存多地图的主函数SaveAtlas /*** brief 保存地图* param type 保存类型*/ void System::SaveAtlas(…

机器学习中的概率与统计知识点汇总

引言 在学习高级知识时&#xff0c;理解基本概念至关重要。为什么&#xff1f;因为基础知识是您构建高级知识的基础。如果你把更多的东西放在薄弱的基础之上&#xff0c;它最终可能会分裂&#xff0c;这意味着你最终无法完全理解你所学的任何知识。因此&#xff0c;让我们尝试…

如何正确选择爬虫采集接口和API?区别在哪里?

在信息时代&#xff0c;数据已经成为了一个国家、一个企业、一个个人最宝贵的资源。而爬虫采集接口则是获取这些数据的重要手段之一。本文将从以下八个方面进行详细讨论&#xff1a; 1.什么是爬虫采集接口&#xff1f; 2.爬虫采集接口的作用和意义是什么&#xff1f; 3.爬虫…

智慧城市政务一网统管解决方案:PPT全文34页,附下载

关键词&#xff1a;智慧政务解决方案&#xff0c;智慧城市解决方案&#xff0c;智慧政务一网统管解决方案&#xff0c;一网统管治理理念&#xff0c;一网统管治理体系&#xff0c;一网统管治理手段&#xff0c;智慧政务综合服务平台建设 一、智慧城市政务一网统管建设背景 一…

CocosCreator 之 Tween缓动系统的使用

版本&#xff1a; 3.4.0 语言&#xff1a; TypeScript 环境&#xff1a; Mac 简介 在CocosCreator 3.x版本后&#xff0c; Tween缓动系统代替了原有的Action动作。官方使用缓动系统的主要目的之一是用于解决离线动画无法满足需求时的动态动画问题。 简单的示例&#xff1a; …

R语言期末考试复习二

上篇文章的后续&#xff01;&#xff01;&#xff01;&#xff01; http://t.csdnimg.cn/sqvYD 1.给向量vec1设置名为"A","B","C","D","E","F","G"。 2.将矩阵mat1的行名设置为"Row1"&#…

8 个适用于电脑的顶级免费分区恢复软件

Windows PC 上的数据管理有时可能会带来压力&#xff0c;尤其是当您有多个分区时。大多数时候&#xff0c;磁盘管理工具使分析磁盘、释放空间甚至创建分区变得非常容易。但有时会发生不可预见的事件&#xff0c;可能导致分区丢失&#xff0c;从而造成潜在的数据灾难。嗯&#x…

ATA-7030高压放大器在等离子体实验中的应用有哪些

高压放大器在等离子体实验中有多种重要应用。等离子体是一种带电粒子与电中性粒子混合的物质&#xff0c;其具有多种独特的物理性质&#xff0c;因此在许多领域具有广泛的应用&#xff0c;例如聚变能源、等离子体医学、材料加工等。下面安泰电子将介绍高压放大器在等离子体实验…

pycharm安装PyQt5及其工具

PyCharm安装PyQt5及其工具&#xff08;Qt Designer、PyUIC、PyRcc&#xff09;详细教程_pycharm pyqt5-CSDN博客 上面是原文链接&#xff0c;根据原文链接&#xff0c;我重新记录一下。IDE&#xff1a;pycharm 2023.2.5 一共需要安装5个。 在PyCharm中如何完整优雅地安装配置…

Spring-SpringFramework特性以及IOC相关知识

SpringFramework五大模块 特性 IOC思想和DI IOC是容器&#xff0c;用于管理资源 IOC&#xff1a;Inversion of Control 反转控制 DI&#xff1a;Dependecy Injection 依赖注入 组件以预先定义好的方式接受来自容器的资源注入 IOC在Spring中的实现 spring提供两种方式&…

2023.11.27如何使用内网穿透工具实现Java远程连接操作本地Elasticsearch搜索引擎

文章目录 前言1. Windows 安装 Cpolar2. 创建Elasticsearch公网连接地址3. 远程连接Elasticsearch4. 设置固定二级子域名 前言 简单几步,结合Cpolar内网穿透工具实现Java远程连接操作本地Elasticsearch。 什么是elasticsearch&#xff1f;一个开源的分布式搜索引擎&#xff0…