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

python编程练习1-数组

1.两数之和

class Solution(object):def twoSum(self, nums, target):""":type nums: List[int]:type target: int:rtype: List[int]"""for i in range(len(nums)):res=target-nums[i]if res in nums[i+1:]:return [i,nums[i+1:].index(res)+i+1]

2. 三数之和(排序+双指针)

    题目中要求找到所有「不重复」且和为 0 的三元组,这个「不重复」的要求使得我们无法简单地使用三重循环枚举所有的三元组。

        「不重复」的本质是什么?我们保持三重循环的大框架不变,只需要保证:

        第二重循环枚举到的元素不小于当前第一重循环枚举到的元素;

        第三重循环枚举到的元素不小于当前第二重循环枚举到的元素。

        也就是说,我们枚举的三元组 (a,b,c) 满足 a≤b≤c。我们可以将数组中的元素从小到大进行排序,随后使用普通的三重循环就可以满足上面的要求。

        同时,对于每一重循环而言,相邻两次枚举的元素不能相同,否则也会造成重复。举个例子,如果排完序的数组为

[0, 1, 2, 2, 2, 3]

        我们使用三重循环枚举到的第一个三元组为 (0,1,2),如果第三重循环继续枚举下 一个元素,那么仍然是三元组 (0,1,2),产生了重复。因此我们需要将第三重循环「跳到」下一个不相同的元素,即数组中的最后一个元素 3,枚举三元组 (0,1,3)

        这种方法的时间复杂度仍然为 O(N3),毕竟我们还是没有跳出三重循环的大框架。然而它是很容易继续优化的,可以发现,如果我们固定了前两重循环枚举到的元素 a 和 b,那么只有唯一的 c 满足 a+b+c=0。当第二重循环往后枚举一个元素 b ′时,由于 b ′>b,那么满足 a+b ′+c ′=0 的 c′,一定有 c′<c,即 c ′在数组中一定出现在 c 的左侧。也就是说,我们可以从小到大枚举 b,同时从大到小枚举 c,即第二重循环和第三重循环实际上是并列的关系。

  有了这样的发现,我们就可以保持第二重循环不变,而将第三重循环变成一个从数组最右端开始向左移动的指针。

  这个方法就是我们常说的「双指针」当我们需要枚举数组中的两个元素时,如果我们发现随着第一个元素的递增,第二个元素是递减的,那么就可以使用双指针的方法,将枚举的时间复杂度从 O(N2) 减少至 O(N)。为什么是 O(N) 呢?这是因为在枚举的过程每一步中,「左指针」会向右移动一个位置(也就是题目中的 b),而「右指针」会向左移动若干个位置,这个与数组的元素有关,但我们知道它一共会移动的位置数为 O(N),均摊下来,每次也向左移动一个位置,因此时间复杂度为 O(N)。

注意到我们的伪代码中还有第一重循环,时间复杂度为 O(N),因此枚举的总时间复杂度为 O(N2)。由于排序的时间复杂度为 O(NlogN),在渐进意义下小于前者,因此算法的总时间复杂度为 O(N2)。

   class Solution:def threeSum(self, nums: List[int]) -> List[List[int]]:  #-> List[List[int]]:这是函数的返回类型提示,表示这个函数应该返回一个由整数列表组成的列表。也就是说,返回值是一个二维数组,其中每个元素本身也是一个整数列表。n = len(nums)nums.sort()ans = list()# 枚举 afor first in range(n):# 需要和上一次枚举的数不相同if first > 0 and nums[first] == nums[first - 1]:continue# c 对应的指针初始指向数组的最右端third = n - 1target = -nums[first]# 枚举 bfor second in range(first + 1, n):# 需要和上一次枚举的数不相同if second > first + 1 and nums[second] == nums[second - 1]:continue# 需要保证 b 的指针在 c 的指针的左侧while second < third and nums[second] + nums[third] > target:third -= 1# 如果指针重合,随着 b 后续的增加# 就不会有满足 a+b+c=0 并且 b<c 的 c 了,可以退出循环if second == third:breakif nums[second] + nums[third] == target:ans.append([nums[first], nums[second], nums[third]])return ans

3.最接近的三数之和「排序+双指针」

解法同题2,采用排序和双指针的方法。

这里的「最接近」即为差值的绝对值最小。我们可以考虑直接使用三重循环枚举三元组,找出与目标值最接近的作为答案,时间复杂度为 O(N3 )。然而本题的 N 最大为 1000,会超出时间限制。

如何进行优化?我们首先考虑枚举第一个元素 a,对于剩下的两个元素 b 和 c,我们希望它们的和最接近 target−a。对于 b 和 c,如果它们在原数组中枚举的范围(既包括下标的范围,也包括元素值的范围)没有任何规律可言,那么我们还是只能使用两重循环来枚举所有的可能情况。因此,我们可以考虑对整个数组进行升序排序,这样一来:

假设数组的长度为 n,我们先枚举 a,它在数组中的位置为 i;

为了防止重复枚举,我们在位置 [i+1,n) 的范围内枚举 b 和 c。

当我们知道了 b 和 c 可以枚举的下标范围,并且知道这一范围对应的数组元素是有序(升序)的,那么我们是否可以对枚举的过程进行优化呢?

答案是可以的。借助双指针,我们就可以对枚举的过程进行优化。我们用 pb和 pc, 分别表示指向 b 和 c 的指针,初始时,pb指向位置 i+1,即左边界;pc指向位置 n−1,即右边界。在每一步枚举的过程中,我们用 a+b+c 来更新答案,并且:

如果 a+b+c≥target,那么就将 pc,向左移动一个位置;

如果 a+b+c<target,那么就将 pb,向右移动一个位置。

小优化

本题也有一些可以减少运行时间(但不会减少时间复杂度)的小优化。当我们枚举到恰好等于 target 的 a+b+c 时,可以直接返回 target 作为答案,因为不会有再比这个更接近的值了。

另一个优化与 15. 三数之和的题解 中提到的类似。当我们枚举 a,b,c 中任意元素并移动指针时,可以直接将其移动到下一个与这次枚举到的不相同的元素,减少枚举的次数。

class Solution:def threeSumClosest(self, nums, target):nums.sort()n = len(nums)best = 10**7   #初始化best的值,定义为一个很大的值# 根据差值的绝对值来更新答案def update(cur):nonlocal best #声明best为非局部变量,可以更新外部函数best的值if abs(cur - target) < abs(best - target):best = cur# 枚举 afor i in range(n):# 保证和上一次枚举的元素不相等if i > 0 and nums[i] == nums[i - 1]:continue# 使用双指针枚举 b 和 cj, k = i + 1, n - 1while j < k:s = nums[i] + nums[j] + nums[k]# 如果和为 target 直接返回答案if s == target:return targetupdate(s)if s > target:# 如果和大于 target,移动 c 对应的指针k0 = k - 1# 移动到下一个不相等的元素while j < k0 and nums[k0] == nums[k]:k0 -= 1k = k0else:# 如果和小于 target,移动 b 对应的指针j0 = j + 1# 移动到下一个不相等的元素while j0 < k and nums[j0] == nums[j]:j0 += 1j = j0return best

4.盛最多水的容器(双指针)

分析:

[1, 8, 6, 2, 5, 4, 8, 3, 7]

在初始时,左右指针分别指向数组的左右两端,它们可以容纳的水量为 min(1,7)∗8=8。

此时我们需要移动一个指针。移动哪一个呢?直觉告诉我们,应该移动对应数字较小的那个指针(即此时的左指针)。这是因为,由于容纳的水量是由

两个指针指向的数字中较小值∗指针之间的距离  决定的。如果我们移动数字较大的那个指针,那么前者「两个指针指向的数字中较小值」不会增加,后者「指针之间的距离」会减小,那么这个乘积会减小。因此,我们移动数字较大的那个指针是不合理的。因此,我们移动 数字较小的那个指针。

有读者可能会产生疑问:我们可不可以同时移动两个指针? 先别急,我们先假设 总是移动数字较小的那个指针 的思路是正确的,在走完流程之后,我们再去进行证明。

所以,我们将左指针向右移动:

[1, 8, 6, 2, 5, 4, 8, 3, 7]
    ^                    ^
此时可以容纳的水量为 min(8,7)∗7=49。由于右指针对应的数字较小,我们移动右指针:

[1, 8, 6, 2, 5, 4, 8, 3, 7]
    ^                 ^
此时可以容纳的水量为 min(8,3)∗6=18。由于右指针对应的数字较小,我们移动右指针:

[1, 8, 6, 2, 5, 4, 8, 3, 7]
    ^              ^
此时可以容纳的水量为 min(8,8)∗5=40。两指针对应的数字相同,我们可以任意移动一个,例如左指针:

[1, 8, 6, 2, 5, 4, 8, 3, 7]
       ^           ^
此时可以容纳的水量为 min(6,8)∗4=24。由于左指针对应的数字较小,我们移动左指针,并且可以发现,在这之后左指针对应的数字总是较小,因此我们会一直移动左指针,直到两个指针重合。在这期间,对应的可以容纳的水量为:min(2,8)∗3=6,min(5,8)∗2=10,min(4,8)∗1=4。

在我们移动指针的过程中,计算到的最多可以容纳的数量为 49,即为最终的答案。

class Solution:def maxArea(self, height: List[int]) -> int:l,r=0,len(height)-1ans=0while l<r:area=min(height[l],height[r])*(r-l)ans=max(ans,area)if height[l]<=height[r]:l+=1 #左指针右移else:r-=1 #右指针左移return ans

 

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【内网】服务器升级nginx1.17.0
  • HarmonyOS 地图服务:深度解析其丰富功能与精准导航实力
  • TCP和UDP编程的学习
  • 【python】灰色预测 GM(1,1) 模型
  • Coze插件发布!PDF转Markdown功能便捷集成,打造你的专属智能体
  • 使用PCF8591实现一个串口控制电压表
  • 第三期书生大模型实战营 进阶岛第3关LMDeploy 量化部署进阶实践
  • Eclipse的使用配置教程:必要设置、创建工程及可能遇到的问题(很详细,很全面,能解决90%的问题)
  • 开发小运维-jar包服务shell启动脚本
  • 提升职业竞争力,亚马逊云科技认证助你云端腾飞
  • 第1节 安装Flask
  • LeetCode.209.长度最小的子数组
  • uniapp 修复使用 uni.saveImageToPhotosAlbum 方法在部分安卓手机上保存失败
  • 生信分析:精准科研的幕后英雄,加速生物医学研究新进程
  • 其他自动重试的注解
  • __proto__ 和 prototype的关系
  • 0x05 Python数据分析,Anaconda八斩刀
  • Android Studio:GIT提交项目到远程仓库
  • eclipse(luna)创建web工程
  • iOS 颜色设置看我就够了
  • mongodb--安装和初步使用教程
  • PHP 7 修改了什么呢 -- 2
  • spring学习第二天
  • SQLServer之索引简介
  • SSH 免密登录
  • 安卓应用性能调试和优化经验分享
  • 闭包,sync使用细节
  • 服务器从安装到部署全过程(二)
  • 高程读书笔记 第六章 面向对象程序设计
  • 官方新出的 Kotlin 扩展库 KTX,到底帮你干了什么?
  • 基于Android乐音识别(2)
  • 如何使用 OAuth 2.0 将 LinkedIn 集成入 iOS 应用
  • 什么软件可以提取视频中的音频制作成手机铃声
  • 微信开源mars源码分析1—上层samples分析
  • 我的业余项目总结
  • 一天一个设计模式之JS实现——适配器模式
  • 异步
  • 深度学习之轻量级神经网络在TWS蓝牙音频处理器上的部署
  • 阿里云API、SDK和CLI应用实践方案
  • 如何正确理解,内页权重高于首页?
  • 新海诚画集[秒速5センチメートル:樱花抄·春]
  • ​MPV,汽车产品里一个特殊品类的进化过程
  • #if等命令的学习
  • #QT(一种朴素的计算器实现方法)
  • $nextTick的使用场景介绍
  • (2)(2.10) LTM telemetry
  • (aiohttp-asyncio-FFmpeg-Docker-SRS)实现异步摄像头转码服务器
  • (floyd+补集) poj 3275
  • (PHP)设置修改 Apache 文件根目录 (Document Root)(转帖)
  • (ZT)出版业改革:该死的死,该生的生
  • (创新)基于VMD-CNN-BiLSTM的电力负荷预测—代码+数据
  • (二)windows配置JDK环境
  • (二十三)Flask之高频面试点
  • (附源码)ssm高校升本考试管理系统 毕业设计 201631
  • (算法)Travel Information Center