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)就可以得到。