数组-双指针

博客介绍了用双指针算法解决LeetCode的两个数组问题。LC209求长度最小的子数组,需明确指针移动条件并用while判断;LC94水果成篮问题,要保证左右指针间元素种类<=2,使用字典存储元素及出现次数,还提及实现时的细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.LC209长度最小的子数组

比较容易想到是用双指针的解法。

定义两个指针left,right分别指向子数组的头和尾;

初始时,left right 都处于列表的第一个元素位置,然后计算这两个指针之间的元素和

当left 和right之间的元素和<target 时,right不断向右移动,right+=1;

当 元素和>=target时:

1.记录此时的子数组长度:right - left -1

2.元素和-left指针指向的数值

3.left向右移动一位

完整代码中除了定义两个指针外,还需要一个存储指针中间元素和的变量temp(初始值为0,后续不断累加)、子数组长度的变量res(初始值为一个很大的数,因为后面要求最小的数组长度,只需要取min(res,right - left -1),若没有符合的子数组即res没有变化还是初始值,那么将res赋为0)

class Solution:

def minSubArrayLen(self, target: int, nums: List[int]) -> int:

left,right = 0,0

temp = 0

res = len(nums) + 1

while right <= len(nums)-1 :

temp += nums[right]

while temp >= target:

res = min(res, right-left +1)

temp -= nums[left]

left +=1

if temp < target:

right += 1

if res == len(nums) + 1:

res = 0

return res

 源自代码随想录代码随想录

其中一个比较重要的点是,当元素和>=target,left指针向右移动时,需要用while,而不是单纯的if条件。这个是一开始出错的点。

因为需要保证left 和right之间的元素和一直是<target的,如果只用一个if,有可能新的left 和right之间的元素和是>=target的,这样再循环下去得到的数组长度肯定不对。

在双指针解法中,很多地方内部判断时都需要用到while,。所以对于双指针而言,首先要明确两个指针的移动条件是什么,在判断是否要移动时,要while判断下这个条件。

2.LC94.水果成篮

这个题和上一个题的区别是,要保证左右指针之间元素的种类 <=2,这就需要一个不同的数据结构来存储遍历的结果。

如果使用数组,只保存遍历过程中的种类,那么判断条件是数组中的个数超过2个。当满足条件时left右移,对应数组中的friuts[left]元素删除掉。那么会有一个问题,如果数组是【1,2,1,1,3】这样排列的,save中只存储【1,2,3】,那么删掉1后,left右移到2的位置,子数组为[2,1,1,3],里面仍然是3个元素,还需要继续剔除,但是save里面已经是两个了,判断失效了。

所以我们除了需要知道元素种类的信息,还需要知道每种元素都出现了几次,字典这种数据结构就解决了这个问题。

当right向右遍历时,每经过一个元素,就以key,value格式存储下来,key为元素种类,value为该元素出现的次数。这样当save中元素种类超过2个时,就让left指向的元素的value减1,left 右移,直到元素种类 <=2。

主体逻辑就是这样的,在具体实现的时候还需要注意一些细节:

当value减1后变为0,需要手动删除该元素,否则会影响后续判断

如何记录过程中拿到最多的果子数?因为每次只能拿一个,所以最多的果子数等价于最长的子数组长度。初始化为0,后续在每次遍历的末尾,求一下max(res,right -left+1)就可以得到。

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值