【PythonCode】力扣Leetcode21~25题Python版

【PythonCode】力扣Leetcode21~25题Python版

前言

力扣Leetcode是一个集学习、刷题、竞赛等功能于一体的编程学习平台,很多计算机相关专业的学生、编程自学者、IT从业者在上面学习和刷题。
在Leetcode上刷题,可以选择各种主流的编程语言,如C++、JAVA、Python、Go等。还可以在线编程,实时执行代码,如果代码通过了平台准备的测试用例,就可以通过题目。
本系列中的文章从Leetcode的第1题开始,记录我用Python语言提交的代码和思路,供Python学习参考。

21. 合并两个有序链表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

示例 1:
在这里插入图片描述
输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
示例 2:
输入:l1 = [], l2 = []
输出:[]
示例 3:
输入:l1 = [], l2 = [0]
输出:[0]
提示:
两个链表的节点数目范围是 [0, 50]
-100 <= Node.val <= 100
l1 和 l2 均按 非递减顺序 排列

代码实现:

class Solution:def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:listm = ListNode(0, next=None)cur = listmwhile list1 and list2:if list1.val <= list2.val:cur.next = list1list1 = list1.nextelse:cur.next = list2list2 = list2.nextcur = cur.nextcur.next = list1 if list1 is not None else list2return listm.next

解题思路:要将两个升序的链表合并成一个新的升序链表,可以从两个链表的头节点开始,依次比较节点的大小,将更小的节点添加到新的链表中。

先新建一个链表,在这个链表中初始化一个值为0的节点,作为前置节点。将待合并的节点依次添加到此链表中,合并完成后返回此链表的第二个节点至末尾,就是需要的结果。

当两个待合并的链表都不为空时,取两个链表的头节点进行比较,并将更小的节点添加到新链表中。节点被添加后,对应链表的头指向下一个节点,相当于将已合并的节点删除。链表头指向的节点不断往后移动,就是两个指针在移动,不断更新链表的头,比较大小时就只需要关注头节点。

当其中一个链表的节点被合并完成后,另一个链表中剩余节点的值都更大,此时,不需要再比较,直接将这些剩余的节点添加到新链表的后面。

在往新链表中添加节点时,也是用一个指针,指针一直都指向新链表的最后一个节点,要添加的节点直接加在指针后面。(链表基础,参考:Python实现单向链表)

22. 括号生成

数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。

示例 1:
输入:n = 3
输出:[“((()))”,“(()())”,“(())()”,“()(())”,“()()()”]
示例 2:
输入:n = 1
输出:[“()”]
提示:
1 <= n <= 8

代码实现:

class Solution:def generateParenthesis(self, n: int) -> List[str]:result = []def backtrack(temp, left, right):if len(temp) == 2 * n:result.append(temp)returnif left < n:temp += '('backtrack(temp, left+1, right)temp = temp[:-1]if right < left:temp += ')'backtrack(temp, left, right+1)temp = temp[:-1]backtrack('', 0, 0)return result

解题思路:本题需要生成n对有效的小括号,小括号由左括号和右括号两个部分组成,最终生成的结果长度为2n,包含n个左括号和n个右括号。在生成有效括号的过程中,右括号的个数不能多于左括号的个数,否则括号是无效的。

本题求的是所有可能的括号组合,可以用回溯法,通过不断的回溯,穷举出所有的组合可能性。参考:循序渐进,搞懂什么是回溯算法。(前面的力扣17题也用了回溯算法,可以结合一起看)

按照回溯法的求解步骤,先定义回溯的解空间,本题是求所有可能的括号组合,所以结果是一个字符串数组。回溯时,搜索树的高度最高为2n,深度优先遍历时每次往字符串中添加一个左括号或右括号。当左括号的个数小于n时,可以往字符串中添加左括号,当字符串中的右括号个数小于左括号个数时,可以往字符串中添加右括号。这样可以保证括号组合一直是有效的,当字符串长度达到2n时,得到一种可能的组合,将组合添加到结果列表中。往回回溯时,去掉字符串的最后一个字符,通过回溯穷举所有的可能性,最后得到所有可能的括号组合。

结合代码,首先初始化结果数组result,回溯时的括号字符串temp。然后定义回溯函数backtrack(),在回溯函数中,如果括号字符串长度达到2n,就找到一种组合,把当前的括号字符串temp保存到result中,如果长度没有达到2n,就继续按括号有效的规则往字符串中添加左括号或右括号,往回回溯时,将上一个添加的括号从temp中移除,也就是将temp中的最后一个字符移除。最后调用回溯函数backtrack(),从左括号和右括号个数都为0个开始,执行回溯函数。

23. 合并 K 个升序链表

给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表。

示例 1:
输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:
链表数组如下:
[
1->4->5,
1->3->4,
2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6
示例 2:
输入:lists = []
输出:[]
示例 3:
输入:lists = [[]]
输出:[]
提示:
k == lists.length
0 <= k <= 10^4
0 <= lists[i].length <= 500
-10^4 <= lists[i][j] <= 10^4
lists[i] 按 升序 排列
lists[i].length 的总和不超过 10^4

代码实现:

class Solution:def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:return self.merge(lists, 0, len(lists)-1)def merge(self, lists, left, right):if left == right:return lists[left]if left > right:returnmid = (left + right) // 2return self.mergeTwoLists(self.merge(lists, left, mid), self.merge(lists, mid+1, right))def mergeTwoLists(self, list1, list2):listm = ListNode(0, next=None)cur = listmwhile list1 and list2:if list1.val <= list2.val:cur.next = list1list1 = list1.nextelse:cur.next = list2list2 = list2.nextcur = cur.nextcur.next = list1 if list1 is not None else list2return listm.next

解题思路:合并k个升序链表是21题合并两个升序链表的升级版,因此我们可以调用合并两个链表的代码,来重复合并操作。最简单的方式就是从第一个和第二个链表开始依次合并,直到合并完k个链表。但这种方式需要合并k-1次,前面的链表被反复遍历,时间复杂度太高,提交代码会超时。

要将时间复杂度降低,就要减少合并的次数,所以考虑的合并策略是二分法合并。用倒推的思路,将k个链表分成两份,如果两部分都合并完成,则将这两个链表合并在一起就完成了,这两个部分再分别递归地往下二分,直到最后分的链表剩一个或两个。

如果从前往后依次合并,假设每个链表的长度为n,第一个和第二个链表合并需要遍历两个链表,时间复杂度为2n,随着每次合并,其中一个链表的长度逐渐变成2n,3n,…,子链表的长度越来越长,需要合并k-1次,最后一次合并时,前k-1个链表合并成的子链表长度为(k-1)*n,与第k个链表合并时间复杂度为k*n,所以整体的时间复杂度为2n+3n+…+kn=(k/2)*k*n(约等于),时间复杂度为O(k2*n)。

使用二分法合并时,最后一次合并两个链表的长度都为(k/2)*n,时间复杂度为k*n。往前推时每次合并的时间复杂度依次分别为(k/2)*n,(k/4)*n,…,并且时间复杂度为(k/2)*n的操作需要做两次,时间复杂度为(k/4)*n的操作需要做四次,以此类推,所以每一轮的合并时间复杂度都为k*n。k个链表二分法合并需要进行logk轮的合并,所以时间复杂度为O(k*logk*n)。O(k*logk*n)的时间复杂度优于O(k2*n)。

最后看一下代码,两个链表合并的代码直接复用,二分法合并时,使用递归的方式对k个链表进行二分,分到剩一个或两个的情况,代码往回递归,完成合并。

24. 两两交换链表中的节点

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

示例 1:
在这里插入图片描述
输入:head = [1,2,3,4]
输出:[2,1,4,3]
示例 2:
输入:head = []
输出:[]
示例 3:
输入:head = [1]
输出:[1]
提示:
链表中节点的数目在范围 [0, 100] 内
0 <= Node.val <= 100

代码实现:

class Solution:def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:prev = ListNode(0, head)temp = prevwhile temp.next and temp.next.next:nodea = temp.nextnodeb = temp.next.nextnodea.next = nodeb.next  # 第一步temp.next = nodeb  # 第二步nodeb.next = nodea  # 第三步temp = nodeareturn prev.next

解题思路:题目要求两两交换链表的节点,也就是将链表的第一个节点与第二个节点交换位置,第三个节点与第四个节点交换位置,… 以此类推,不能修改节点内部的值,也就是不能将第一个节点的值改成第二个节点的值,第二个节点的值改成第一个节点的值。

要满足节点的交换,就是要修改节点的next指向关系,为了方便说明,可以参考下图:

在这里插入图片描述
创建一个前置节点,将前置节点的next指向链表的头,创建一个临时指针指向前置节点,创建两个指针指向临时节点后面的两个节点,这两个节点就是需要交换位置的节点。

交换需要执行三次next指针修改,分为三个步骤:

第一步,将第一个节点的next指向第二个节点的next(也就是指向第三个节点,可能为空)。

第二步,将前置节点的next指向第二个节点。

第三步,将第二个节点的next指向第一个节点。

修改next指针后,原来的指针“断掉”了,此时,看链表新的指向关系(图中红线),第一个节点和第二个节点的位置已经交换了。

在这里插入图片描述

要继续交换链表后面的节点(如第三个和第四个),将临时指针指向第三个节点的前一个节点,也就是节点1,并更新临时指针后两个指针指向的节点。如此循环,直到链表中的节点剩余0个或1个,则交换完成。返回前置节点的后一个节点就是结果。

25. K 个一组翻转链表

给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。

k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

示例 1:
在这里插入图片描述
输入:head = [1,2,3,4,5], k = 2
输出:[2,1,4,3,5]
示例 2:
在这里插入图片描述
输入:head = [1,2,3,4,5], k = 3
输出:[3,2,1,4,5]
提示: 链表中的节点数目为 n
1 <= k <= n <= 5000
0 <= Node.val <= 1000

代码实现:

class Solution:def reverseKGroup(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:prev = ListNode(0, head)temp = prevk_head = head while k_head:node = []cur = tempfor _ in range(k):node.append(cur.next)cur = cur.nextif not cur:return prev.nextk_head = cur.nextnode[0].next = k_head  # 第一步temp.next = node[-1]  # 第二步for i in range(1, k):  # 第三步node[i].next = node[i-1]temp = node[0]return prev.next

解题思路:本题是上一题24题的升级版,上一题是两两翻转节点的位置,本题是k个一组翻转(所以要先看懂上一题再看本题)。翻转思路与两两翻转的思路相通,在两两翻转的时候,每一组的节点是两个。

k个节点一组翻转时,翻转方法也可以分为三个步骤,为了方便说明,可以参考下图:

在这里插入图片描述

首先还是创建一个前置节点,将前置节点的next指向链表的头,创建一个临时指针指向前置节点。不同的是这里创建一个k_head指针指向k个结点的头,以便代码中找到这k个结点。

第一步,将这组节点中的第一个节点的next指向最后一个节点的next。

第二步,将临时指针的next指向这组节点的最后一个节点。

第三步,在这组节点内部,将除第一个节点的next都指向它的前一个节点。

执行这三步后,就完成了一组节点的翻转。此时将临时指针指向组内的第一个节点,该节点就是下一组待翻转节点的前置节点,并更新k_head指针,如此循环,当链表中剩余的节点数量不足k个时,翻转完成,返回前置节点的后一个节点,就是本题的结果。


相关阅读

【PythonCode】力扣Leetcode16~20题Python版

📢欢迎 点赞👍 收藏⭐ 评论📝 关注 如有错误敬请指正!

☟ 学Python,点击下方名片关注我。☟

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

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

相关文章

如何将HTTP升级成HTTPS?既简单又免费的方法!

在当今数字化时代&#xff0c;网络安全已成为用户和企业关注的焦点。HTTPS作为一种更加安全的网络通信协议&#xff0c;正逐渐取代传统的HTTP成为新的标准。对于许多网站管理员和内容创作者来说&#xff0c;如何免费升级到HTTPS是一个值得探讨的问题。本文将详细介绍一些免费的…

一分钟学习数据安全—自主管理身份SSI加密技术

上篇介绍了SSI的架构。架构之后&#xff0c;我们要了解一下SSI发展的驱动力&#xff1a;加密技术。现代数字通信离不开数学和计算机科学&#xff0c;加密技术也源于此。加密技术使区块链和分布式账本得以实现&#xff0c;也使SSI成为可能。 以下我们就概览一下SSI基础架构中涉及…

前端三大主流框架

目录 1.概述 2.React 2.1.作用 2.2.诞生背景 2.3.版本历史 2.4.优缺点 2.5.应用场景 2.6.示例 2.7.未来展望 3.Vue 3.1.作用 3.2.诞生背景 3.3.版本历史 3.4.优缺点 3.5.应用场景 3.7.示例 3.8.未来展望 4.Angular 4.1.作用 4.2.诞生背景 4.3.版本历史 4…

2 程序的灵魂—算法-2.2 简单算法举例-【例 2.5】

【例 2.5】对一个大于或等于 3 的正整数&#xff0c;判断它是不是一个素数。 算法可表示如下&#xff1a; S1: 输入 n 的值 S2: i2 S3: n 被 i 除&#xff0c;得余数 r S4:如果 r0&#xff0c;表示 n 能被 i 整除&#xff0c;则打印 n“不是素数”&#xff0c;算法结束&#xf…

【介绍下R-tree,什么是R-tree?】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

【Java】解决Java报错:ArrayIndexOutOfBoundsException

文章目录 引言1. 错误详解2. 常见的出错场景2.1 直接访问数组越界2.2 循环中的索引错误2.3 多维数组的错误访问 3. 解决方案3.1 检查数组长度3.2 正确使用循环3.3 多维数组的正确访问 4. 预防措施4.1 使用增强型 for 循环4.2 编写防御性代码4.3 单元测试 结语 引言 在Java编程…

力扣面试题17.18.最短超串

力扣面试题17.18.最短超串 类似76. 用哈希表处理短数组 然后遍历长数组 找到相同元素 count– –当count0时进入循环 —— 尽可能缩小区间 class Solution {public:vector<int> shortestSeq(vector<int>& big, vector<int>& small) {int nbig.si…

mysql报错 Duplicate entry

在MySQL中&#xff0c;当你尝试执行插入&#xff08;INSERT&#xff09;或更新&#xff08;UPDATE&#xff09;操作时&#xff0c;如果目标表中存在唯一索引&#xff08;包括主键索引、唯一约束索引等&#xff09;&#xff0c;并且你要插入或更新的数据在该索引列上的值与表中已…

双网卡配置IP和路由总结

1.在网络适配器属性IPv4中设置默认网关&#xff08;记网关地址为A&#xff09;&#xff0c;将会在本地路由表中新增一条记录&#xff1a; 网络号子网掩码网关地址0.0.0.00.0.0.0A 2.如果有两个网卡&#xff08;假设一个连接内网&#xff0c;一个连接互联网&#xff09;&#…

20240607在Toybrick的TB-RK3588开发板的Android12下适配IMX415摄像头和ov50c40

20240607在Toybrick的TB-RK3588开发板的Android12下适配IMX415摄像头和ov50c40 2024/6/7 11:42 【4K/8K摄像头发热量巨大&#xff0c;请做好散热措施&#xff0c;最好使用散热片鼓风机模式&#xff01;】 结论&#xff1a;欢迎您入坑。 Toybrick的TB-RK3588开发板的技术支持不…

【C语言进阶】--- 字符串函数与内存函数

字字符串函数 1.strlen函数 size_t strlen(const char* str); 功能&#xff1a;计算指针str指向的字符串的字符个数 字符串以’\0’作为结束标志&#xff0c;strlen函数返回的是字符串中’\0’前面出现的字符个数&#xff08;不包括’\0’&#xff09; 参数指向的字符串必须要…

使用 TinyEngine 低代码引擎实现三方物料集成

本文由体验技术团队 TinyEngine 项目成员炽凌创作&#xff0c;欢迎大家实操体验&#xff0c;本体验内容基于 TinyEngine 低代码引擎提供的环境&#xff0c;介绍了如何通过 TinyEngine 低代码引擎实现三方物料集成&#xff0c;帮助开发者快速开发。 知识背景 1.1 TinyEngine 低…

【SkyWalking】使用PostgreSQL做存储K8s部署

拉取镜像 docker pull apache/skywalking-ui:10.0.1 docker tag apache/skywalking-ui:10.0.1 xxx/xxx/skywalking-ui:10.0.1 docker push xxx/xxx/skywalking-ui:10.0.1docker pull apache/skywalking-oap-server:10.0.1 docker tag apache/skywalking-oap-server:10.0.1 xxx…

如何在Python中创建和使用自定义模块

在Python中创建和使用自定义模块非常简单。以下是一个基本的步骤指南&#xff1a; 1. 创建自定义模块 首先&#xff0c;你需要创建一个Python文件来作为你的模块。这个文件可以包含任何有效的Python代码&#xff0c;包括函数、类、变量等。让我们创建一个简单的模块&#xff…

VmWare的网络配置说明

VMware的网络配置提供了多种选项&#xff0c;以支持虚拟机与物理机之间的通信&#xff0c;以及虚拟机之间的通信。这些配置包括桥接模式、网络地址转换模式&#xff08;NAT&#xff09;和仅主机模式&#xff0c;每种模式都有其特定的适用场景。 桥接模式&#xff08;Bridged&a…

SpringBoot集成ireport打印,并解决PDF中文显示问题

1、相关jar包引入 <!-- ireport报表相关 start--><dependency><groupId>net.sf.jasperreports</groupId><artifactId>jasperreports</artifactId><version>4.5.1</version><exclusions><exclusion><groupId…

Ubuntu 22.04.4 LTS安装cmake-3.29.5

一、下载源码 wget https://github.com/Kitware/CMake/releases/download/v3.29.5/cmake-3.29.5.tar.gz tar -xzvf cmake-3.29.5.tar.gz 二、编译 运行./bootstrap。 如果出现下列问题&#xff1a; -- Could NOT find OpenSSL, try to set the path to OpenSSL root folder …

go语言后端开发学习(二)——基于七牛云实现的资源上传模块

前言 在之前的文章中我介绍过我们基于gin框架怎么实现本地上传图片和文本这类的文件资源(具体文章可以参考gin框架学习笔记(二) ——相关数据与文件的响应)&#xff0c;但是在我们实际上的项目开发中一般却是不会使用本地上传资源的方式来上传的&#xff0c;因为文件的上传与读…

Spring Security系列之Handler

概述 与Spring、Spring MVC、Spring Boot一样&#xff0c;Spring Security里也有很多Handler接口、可以分为两大类&#xff0c;一类是普通的XxxHandler&#xff08;见名知意&#xff09;&#xff0c;另一类是对应的ServerXxxHandler&#xff08;RequestRejectedHandler除外&am…

gitlab远端指定分支回退到之前的版本

要在GitLab远端指定分支回退到之前的版本&#xff0c;你可以先在本地回退&#xff0c;然后强制推送到远端。以下是步骤和示例代码&#xff1a; 1.检出到你想要回退的分支&#xff1a; git checkout your-branch-name2.使用git log查找你想要回退到的提交的commit ID&#xff…