双指针一般针对多数组排序、同一数组查找元素等的情况,分别指向两个数组的头部或尾部。
leetcode上一些用到双指针的题目
1. 88 合并两个有序数组
class Solution:
def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
"""
Do not return anything, modify nums1 in-place instead.
"""
sorted = []
p1, p2 = 0, 0
while p1 < m or p2 < n:
if p1 == m:
sorted.append(nums2[p2])
p2 += 1
elif p2 == n:
sorted.append(nums1[p1])
p1 += 1
elif nums1[p1] < nums2[p2]:
sorted.append(nums1[p1])
p1 += 1
else:
sorted.append(nums2[p2])
p2 += 1
nums1[:] = sorted
2. 剑指offer 57 和为s的两个数字
由于本题中的数组为递增排序数组,可以对问题进行简化,不断移动头尾两个指针,判断两者和与target的大小,另外需要注意的是,头尾指针不能重合(即i!=j)。
代码如下:
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
# 查找数字n和target-n
# 双指针
i, j = 0, len(nums)-1
while i<j:
if target-nums[j]<nums[i]:
j-=1
elif target-nums[j]>nums[i]:
i+=1
else:
return [nums[i], nums[j]]
return []
3. 剑指offer 57-2 和为s的连续正数
通过一个双指针构建的滑动窗口对窗口内的序列进行求和,若结果等于目标则添加列表,若结果小于目标则移动右边界,若结果小于目标则移动左边界;而当只有两个数字时,仍大于目标,此时移动左边界就与右边界重合了,这时候退出循环,查找结束。
class Solution:
def findContinuousSequence(self, target: int) -> List[List[int]]:
# 双指针法->滑动窗口法
left, right, s, res = 1, 2, 3, []
while left<right:
if s==target:
res.append(list(range(left, right+1)))
s-=left
left+=1
elif s< target: # 扩充右边界
right+=1
s += right
elif s > target: # 缩减左边界
s -= left
left+=1
return res
4. 剑指offer 58 -1 翻转单词顺序
本题由于是要翻转顺序,因此采用双指针从末尾开始移动,构建一个单词的窗口并保存;首先左指针找到第一个空格,保存第一个单词,然后移动右指针到下一个单词位置,这里移动时候可能会遇到右指针指向空格,因此需要额外处理,就这样直到单词遍历。
class Solution:
def reverseWords(self, s: str) -> str:
# 同样可以双指针算法,应该说是滑动窗口法
s_ls = s.strip() # 去除首尾空格
left = right = len(s_ls)-1 # 剑指末尾先
string = []
while left>=0: # 设法处理多个空格
if left == 0: # 到头了
string.append(s_ls[left:right+1])
break
if s_ls[right] == ' ': # 右边为空
right -= 1
if s_ls[left] == ' ' and s_ls[left+1]!=' ':# 第一个空格
string.append(s_ls[left+1:right+1])
right = left-1
left -= 1
return ' '.join(string)