【Leetcode】top 100 双指针

283 移动零

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

分析:双指针初始为0;left指针找零值,right指针找非零值;由于需要保持非零元素的相对顺序,right只能在left的右边寻找(这里不要将right=left+1,会造成right的回退)结束循环条件 right < len(nums);

class Solution(object):def moveZeroes(self, nums):""":type nums: List[int]:rtype: None Do not return anything, modify nums in-place instead."""i, j, m = 0, 0, len(nums)while j < m:   if nums[i] == 0:while j < m: if nums[j] != 0:  #j指向i后第一个非零值nums[i], nums[j] = nums[j], nums[i]break                  j+=1    i, j = i+1, j+1return nums
11 盛最多的水的容器

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。返回容器可以储存的最大水量。

分析:双指针指向一头一尾,使宽度最大;

在移动指针时,宽度减小,只能通过用更大的高度值替换现有较小的高度值来增加水量;

当height[left] < height[right]时,移动left指针,若找到比height[left]更大的元素时,更新水量和left指针;

                                                                         若找不到比height[left]更大的元素时,当前水量为最大;

class Solution(object):def maxArea(self, height):""":type height: List[int]:rtype: int"""out = min(height[0], height[-1]) * (len(height) - 1)left, right = 0, len(height) - 1while left < right:if height[left] < height[right]:           #移动左侧idx = left+1while idx < right:if height[idx] > height[left]:     #可能需要更新out = max(out, min(height[idx],height[right]) * (right-idx))breakidx+=1left = idxelse:idx = right-1while idx > left:if height[idx] > height[right]:     #可能需要更新out = max(out, min(height[idx],height[left]) * (idx-left))   breakidx-=1right = idxreturn out

官方思路:不在乎height[idx] 和 height[left] 的大小,反正left指针需要更新到height[left] > height[right]

class Solution(object):def maxArea(self, height):""":type height: List[int]:rtype: int"""left, right, out = 0, len(height) - 1, 0while left < right:if height[left] < height[right]:           out = max(out, height[left] * (right-left))left += 1else:out = max(out, height[right] * (right-left))   right -= 1return out
  • 相当于用增加的idx内存换out更新次数的减少;

  • 还有一个提前结束的条件: out >= max(height) * (right - left)   因为再更新也无法找到更大的高度值;
15 三数之和

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。

分析:当固定nums[i]时,该问题转为在nums[i:]中找到两数之和为-nums[i],可以搭配hashmap;

          去重处理...本来想用set的自动去重,但list不满足可哈希条件,无法实现set(list),这里list为二维或更高维列表...还是选择用hashmap:键用tuple,这里需要搭配排序使三元组中元素的相对位置一致;

class Solution(object):def threeSum(self, nums):""":type nums: List[int]:rtype: List[List[int]]"""out = {}for i in range(len(nums)-1):hashmap = {}for j, num in enumerate(nums[i+1:]):if -nums[i]-num in hashmap:outt = [nums[i], num, -nums[i]-num]outt.sort()out[tuple(outt)] = jelse:hashmap[num] = j return list(out)#改变排序位置
class Solution(object):def threeSum(self, nums):""":type nums: List[int]:rtype: List[List[int]]"""out = {}nums.sort()for i in range(len(nums)-1):hashmap = {}for j, num in enumerate(nums[i+1:]):if -nums[i]-num in hashmap:out[tuple([nums[i], num, -nums[i]-num])] = jelse:hashmap[num] = j return list(out)#时间复杂度过高O(nlogn)+O(n^2)+O(n)?

官方思路:同样先进行排序,再用一层循环固定一个值,将其转换为两数之和,这里要求固定的值不出现重复;在两数之和问题上使用一头一尾双指针,因为b+c=-a,随着b的增大c必然要减小,这里要求b的值不出现重复,自然c的值就不会出现重复

优化点:提前结束条件:最小三个值的和大于0或最大三个值的和小于零

class Solution(object):def threeSum(self, nums):""":type nums: List[int]:rtype: List[List[int]]"""nums.sort()if sum(nums[0:3])>0 or sum(nums[-3:])<0: return []out = []for i in range(len(nums)):if i>0 and nums[i] == nums[i-1]:continue               #nums[i]不重复left, right = i+1, len(nums)-1while left<right:if left>i+1 and nums[left]==nums[left-1]:          #nums[j]不重复left+=1continueif nums[left]+nums[right]<-nums[i]:left+=1elif nums[left]+nums[right]>-nums[i]:right-=1else:out.append([nums[i],nums[left],nums[right]])   left, right = left+1, right-1         return out
 42 接雨水

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

分析:用减法更方便计算

          以 [a,b,c,d,e]为例:固定a时,要在[b,c,d,e]中找到>=a的第一个值(假设是c),故a-c蓄水ax1-b—ac宽度好计算,但需要用变量储存ac中间的体积;

                                         固定c时,要在[d,e]中找到>=c的第一个值(假设不存在),故c无法作为较小的壁蓄水;改判断c作为较大的壁蓄水:在向右遍历时添加一个指向[d,e]第一个最大值的指针mid,同时也需要用变量储存c-mid中间的体积;

class Solution(object):def trap(self, height):""":type height: List[int]:rtype: int"""left, mid, right = 0, [1,0], [1,0]out = 0while left < len(height)-1:flag = 1while right[0] < len(height):if height[right[0]] >= height[left]:     #找到>=height[left]的值out += height[left]*(right[0]-left-1)-right[1]flag = 0breakelse:if height[right[0]] > height[mid[0]]:mid = right[:]           #mid更新right[0], right[1] = right[0]+1, right[1]+height[right[0]]if flag:                                    #遍历找不到>=height[left]的值out += height[mid[0]]*(mid[0]-left-1)-mid[1]left = mid[0]mid, right = [left+1, 0], [left+1, 0]else:left = right[0]mid, right = [left+1, 0], [left+1, 0]return out#时间复杂度太大,巨长的案例会超出时间限制

官方思路

思路一:动态规划:对于下标 i 能接住的雨水为左侧最大值和右侧最大值的最小值减去 height[i]

用leftmax[i]代表[:i]的最大值,用rightmax[i]代表[i:]的最大值,

递推式:leftmax[i] = max( leftmax[i-1], height[i] )  

              rightmax[i] = max( rightmax[i+1], height[i] )     这里发现rightmax适合倒序遍历

边界条件:leftmax[0] = height[0]

                  rightmax[-1] = height[-1] 

class Solution(object):def trap(self, height):""":type height: List[int]:rtype: int"""leftmax, rightmax = [height[0]], [height[-1]]for i in range(1,len(height)):leftmax.append(max(leftmax[i-1], height[i]))rightmax.insert(0, max(rightmax[-i], height[-i-1]))#左右遍历合并out = 0for i in range(len(height)):out += min(leftmax[i], rightmax[i]) - height[i]return out
#return sum(min(leftmax[i], rightmax[i])-height[i] for i in range(n))

思路二:双指针:使用双指针来缩减动态规划中的空间开销;

因为对于下标 i 能接住的雨水为左侧最大值和右侧最大值的最小值减去 height[i],所以已知左侧最大值和右侧最大值的大小关系时,该式可简化,对应更新left/right指针的下标即可;

class Solution:def trap(self, height):out = 0left, right = 0, len(height) - 1leftmax = rightmax = 0while left < right:leftmax = max(leftmax, height[left])rightmax = max(rightmax, height[right])if leftmax < rightmax:                  out += leftmax - height[left]left += 1else:out += rightmax - height[right]right -= 1return out

思路三:两个方向计算当前最高值围成的有效面积,该面积=矩形面积+柱子面积+积水面积

class Solution(object):def trap(self, height):""":type height: List[int]:rtype: int"""# 同时从左往右和从右往左计算有效面积s1, s2 = 0, 0max1, max2 = 0, 0for i in range(len(height)):if height[i] > max1:max1 = height[i]if height[-i-1] > max2:max2 = height[-i-1]s1 += max1s2 += max2# 积水面积 = S1 + S2 - 矩形面积 - 柱子面积res = s1 + s2 - max1 * len(height) - sum(height)return res

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

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

相关文章

VUE3 显示Echarts百度地图

本次实现最终效果 技术基础以及环境要求 vue3 echarts 百度地图API 要求1&#xff1a; VUE3 环境搭建&#xff1a;https://blog.csdn.net/LQ_001/article/details/136293795 要求2&#xff1a; VUE3 echatrs 环境搭建:https://blog.csdn.net/LQ_001/article/details/1363…

【MATLAB第98期】基于MATLAB的MonteCarlo蒙特卡罗结合kriging克里金代理模型的全局敏感性分析模型【更新中】

【MATLAB第98期】基于MATLAB的Monte Carlo蒙特卡罗结合kriging克里金代理模型的全局敏感性分析模型【更新中】 PS:因内容涉及较多&#xff0c;所以一时半会更新不完 后期会将相关原理&#xff0c;以及多种功能详细介绍。 麻烦点赞收藏&#xff0c;及时获取更新消息。 引言 在…

Go编程实战:高效利用encoding/binary进行数据编解码

Go编程实战&#xff1a;高效利用encoding/binary进行数据编解码 引言encoding/binary 包核心概念ByteOrder 接口Binary 数据类型的处理处理复杂数据结构 基础使用教程数据类型与二进制格式的映射基本读写操作写操作 - binary.Write读操作 - binary.Read 错误处理 高级功能与技巧…

定时执行专家V7.1 多国语言版本日文版发布 - タスク自動実行ツールV7.1 日本語版リリース

◆ 软件介绍  ソフトの紹介 《定时执行专家》是一款制作精良、功能强大、毫秒精度、专业级的定时任务执行软件。软件具有 25 种【任务类型】、12 种【触发器】触发方式&#xff0c;并且全面支持界面化【Cron表达式】设置。软件采用多线程并发方式检测任务触发和任务执行&…

CentOS7 Sqoop 1.4.7 安装 (Hadoop 3.3.0)

CentOS7 Sqoop 1.4.7 安装 (Hadoop 3.3.0) 1、 Sqoop 1.4.7 官网链接下载&#xff1a; https://archive.apache.org/dist/sqoop/1.4.7/ 2、把压缩包用mobaxterm拖到 /tools文件夹 3、解压 tar -zvxf /tools/sqoop-1.4.7.bin__hadoop-2.6.0.tar.gz -C /training/4、进入 /t…

基于深度学习的交通标志检测识别系统(含UI界面、yolov8、Python代码、数据集)

项目介绍 项目中所用到的算法模型和数据集等信息如下&#xff1a; 算法模型&#xff1a;     yolov8 yolov8主要包含以下几种创新&#xff1a;         1. 添加注意力机制&#xff08;SE、CBAM等&#xff09;         2. 修改可变形卷积&#xff08;DySnake-主干c…

moi3D安装

下载文件双击文件 下一步 同意下一步 下一步 下一步 下一步 安装下一步 完成 破解 将如图中的文件复制到文件目录下 汉化 在目录中进入ui文件夹下 在安装包中找到如下的文件复制到ui目录下 在打开 另存为 另存为时改一下编码格式如图 打开软件 找到如图options进入…

蓝牙 | 软件: Qualcomm BT Audio 问题分析(4)----检查MIPS使用情况

大家好&#xff01; 我是“声波电波还看今朝”成员的一位FAE Devin.wen&#xff0c;欢迎大家关注我们的账号。 今天给大家大概讲解“如何排查Qualcomm BT Audio”的疑难杂症&#xff08;四&#xff09;&#xff1a;MIPS检查。 如果大家还没有注册我们大大通的账号&#xff0c…

Spring AOP(二) — 底层组件

Spring AOP 是通过动态代理的方式来实现&#xff0c;主要是通过Pointcut、Advice、Advisor及ProxyFactoryBean 等接口来创建代理对象。 在IoC容器中&#xff0c;Advice 是一个bean&#xff08;这样可以在通知中使用其他的bean&#xff09;&#xff0c;而Pointcut虽然不是一个B…

YOLO v1讲解

YOLO是最经典的一阶目标检测框架&#xff0c;记录一下v1思路。 整体流程 输入数据一张 448 448 3 448 \times 448 \times 3 4484483 的图片&#xff0c;切分成 7 7 7 \times 7 77 的网格将图片经过多层CNN&#xff0c;下采样得到 7 7 30 7 \times 7 \times 30 7730 的f…

JVM-对象创建与内存分配机制深度剖析 3

JVM对象创建过程详解 类加载检查 虚拟机遇到一条new指令时&#xff0c;首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用&#xff0c;并且检查这个 符号引用代表的类是否已被加载、解析和初始化过。如果没有&#xff0c;那必须先执行相应的类加载过程。 new…

在分布式环境中使用状态机支持数据的一致性

简介 在本文中&#xff0c;我们将介绍如何在分布式系统中使用transaction以及分布式系统中transaction的局限性。然后我们通过一个具体的例子&#xff0c;介绍了一种通过设计状态机来避免使用transaction的方法。 什么是数据库transaction Transaction是关系型数据普遍支持的…