双指针算法的第三篇,题目的类型与前面都不同,鄙人给这个思想起了个不太合适的名字——滑动窗,其实与第一种两数求和的思想差不多,不同点大概是,滑动窗强调的是双指针之间的数组,求和问题只是一头一尾的遍历操作,关注的是双指针所在位置的元素,包括元素交换一类的也是关注的是指针所在位置的元素。因此用窗口一词形容我们的观察对象是双指针之间的所有元素。
应用场景之滑动窗口
713. Subarray Product Less Than K
Your are given an array of positive integers nums
.
Count and print the number of (contiguous) subarrays where the product of all the elements in the subarray is less than k
.
Input: nums = [10, 5, 2, 6], k = 100
Output: 8
Explanation: The 8 subarrays that have product less than 100 are: [10], [5], [2], [6], [10, 5], [5, 2], [2, 6], [5, 2, 6].
Note that [10, 5, 2] is not included as the product of 100 is not strictly less than k.
class Solution:
def numSubarrayProductLessThanK(self, nums, k):
cn = 0
if k <= 1:
return cn
start = 0
end = 0
cn = 0
prod = 1
while end < len(nums):
prod *= nums[end]
end += 1
while prod >=k:
prod /= nums[start]
start += 1
cn += end -start
return cn
题目中用到start, end 两个指针,prod为两个指针之间元素的乘积, 每次加的cn意思是从start指针的元素开始的符合条件的子数组的和。
11. Container With Most Water
Given n non-negative integers a1, a2, ..., an , where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water.
Note: You may not slant the container and n is at least 2.
看题目也知道,我们需要两个指针,找到装水最多的容器的两条边。想用O(n^2)的暴力法解决肯定是不行的,我们要用two pointer 在O(n)内遍历可能装水最多的两个位置。i, j 两个指针从首尾向中间走,记住当前最大的容积max_v 以及 上一次最大高度h(不是最大容积对应的高度)。原理是这样的,i ,j 向中间走时,容器的宽度在减少,所以只有高度比当前最高高度h 大的,才有可能容积大,i和j的位置可能是依次移动的,比如当前为左边大,我们会移动右边找到更大的边,算一下容积,无论大小,h更新了,且为右边,此时需要移动左指针,找到更大的边,更新高度...。
因此题目的思路就是从两头向中间,找更高的两条边,计算容积,与保留的最大值比较,而不满足最高高度增加的指针位置,不用去计算容积。
class Solution(object):
def maxArea(self, height):
"""
:type height: List[int]
:rtype: int
"""
l = len(height)
max_v = 0
i, j = 0, l-1
while i<j:
x, y = height[i], height[j]
h = min(x,y)
vol = h * (j-i)
if vol > max_v: max_v = vol
while height[i]<=h and i<j:
i += 1
while height[j]<=h and i<j:
j -= 1
return max_v
这道题还不算难理解,而且也不算是滑动窗吧。看下面一道题,也是装水的问题,思路就不太一样了~
42. Trapping Rain Water
Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.
The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped. Thanks Marcosfor contributing this image!
看图确实方便理解问题,但是却基本上毫无头绪 = =,试了好久各种错,干脆直接看了答案。
装水的问题已经见过一次了,这一题所有给出的元素都是一条边,都要装水用。从首尾向中间(以左指针为例),记录当前最大高度maxleft,向中间移动并装水 water+= 就是当前元素位置可以装水的量;left和right指针的比较是比较难理解的地方,可以理解为移动短板,事实上,通过比较maxleft 和maxright,最后两个指针将相遇在全局最高点,装水也就结束了。
class Solution:
def trap(self, height):
"""
:type height: List[int]
:rtype: int
"""
if len(height) == 0:
return 0
left, right = 0, len(height)-1
maxleft, maxright = height[left], height[right]
water = 0
while left < right:
if height[left] < height[right]:
maxleft = max(maxleft,height[left])
water += maxleft - height[left]
left += 1
else:
maxright = max(maxright,height[right])
water += maxright - height[right]
right -= 1
return water
OK,双指针就到这儿了,后面还会有双指针和其他知识的结合,多多指教~
下面几节还是继续刷几道数组相关的题目~