双指针:两头看策略;
1 移动零
给定一个数组
nums
,编写一个函数将所有0
移动到数组的末尾,同时保持非零元素的相对顺序。请注意 ,必须在不复制数组的情况下原地对数组进行操作。
示例 1:
输入: nums =[0,1,0,3,12]
输出:[1,3,12,0,0]
示例 2: 输入: nums =[0]
输出:[0]
思考:
left 指针, index指针;
left指针: left指针左边都不能为0;
index指针:index 指向当前的访问元素;
快速排序也是双指针;
如果访问的当前元素不是0,那就与最左边的元素交换 left+=1, right+=1;
如果访问的当前元素是0, 那就righ指针动就行了
left = 0, right = 0
while right < len(nums):
if num[right]!=0:
num[right], num[left] = num[left],num[right]
left += 1
right += 1
2 乘最多水的容器
给定一个长度为
n
的整数数组height
。有n
条垂线,第i
条线的两个端点是(i, 0)
和(i, height[i])
。找出其中的两条线,使得它们与
x
轴共同构成的容器可以容纳最多的水。返回容器可以储存的最大水量。
说明:你不能倾斜容器。
输入:[1,8,6,2,5,4,8,3,7] 输出:49 解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。思考:
1 求容量最大;
先用两个指针 left = 0, right = len(nums) - 1,从两头浏览,那么容量计算 = 低*高,高 = min(unms[left],nums[right]);
那么如何摆动,两个指针呢? 那个小移动哪一个。
这个如何证明: 想象一下无论移动左指针、还是右指针,都会带来低的减一,所以高减少的越少越好。
class Solution:
def maxArea(self, height: List[int]) -> int:
left = 0
right = len(height) - 1
vio = 0
while left <= right:
h = min(height[left],height[right])
temp = h * (right - left)
vio = max(vio, temp)
if height[left] < height[right]:
left += 1
else:
right -= 1
return vio
3 三数之和
给你一个整数数组
nums
,判断是否存在三元组[nums[i], nums[j], nums[k]]
满足i != j
、i != k
且j != k
,同时还满足nums[i] + nums[j] + nums[k] == 0
。请你返回所有和为
0
且不重复的三元组。注意:答案中不可以包含重复的三元组。
这个没有时间限定一说:
所以可以巧妙使用排序(升序),然后再加上两数之和的思想;
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
if len(nums)<3 or (len(nums)==3 and sum(nums)!=0):
return []
result = []
# 排序
nums.sort()
for i in range(len(nums)-2):
# 最小的数 都大于0,就不会出现 三个数之和等于零的
if i==0 and nums[i]>0:
return []
# 不能有重复的,
if i!=0 and nums[i]==nums[i-1]:
continue
# nums【i+1:】
a = i+1
b = len(nums)-1
while a<b:
curr = nums[a]+nums[b]
# 存在三个数之和等于0 的
if curr+nums[i]==0:
result.append([nums[i],nums[a],nums[b]])
a+=1
# 是否重复
while a<b and nums[a]==nums[a-1]:
a+=1
b-=1
# 右边界缩紧,是否重复
while a<b and nums[b]==nums[b+1]:
b-=1
# 三个数之和太小,所以a+=1
elif curr+nums[i]<0:
a+=1
else:
b-=1
return result
4 接雨水
给定
n
个非负整数表示每个宽度为1
的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。这一个题目难度还是挺大的,也是值得理解的,直接上思路吧:
思考当前能容纳多少容量的水由什么决定呢?肯定是左边最高的挡板,右边最高的挡板。
每次计算只计算当前位置能容纳的水,然后加起来。
所以:
1 需要存储当前位置最左边挡板最高;
2 需要存储当前位置最右边挡板最高;
当前位置能容纳 = min(当前位置最左边挡板最高,当前位置最右边挡板最高) - height[i]
class Solution:
def trap(self, height: List[int]) -> int:
# 计算每一个柱子存水量是多少,
# 一个柱子的存水量 = min(当前柱子左边最高,当前柱子右边最高) - hight[index]
left_nums = height[:]
right_nums = height[:]
length = len(height)
for i in range(1,length):
left_nums[i] = max(left_nums[i-1], height[i])
for i in range(length-2,0,-1):
right_nums[i] = max(right_nums[i+1], height[i])
sum_waters = 0
for i in range(1,length):
waters = min(left_nums[i],right_nums[i]) - height[i]
if waters<0:
waters = 0
sum_waters += waters
#print(left_nums, right_nums)
return sum_waters