Python版数据结构与算法-双指针,对撞指针、快慢指针、滑动窗口、归并排序
是指在对象时,使用两个或多个来遍历及相应的操作的。暴力算法往往可以优化为双指针算法。
·
双指针 DualPointer
1、基本概念
双指针算法是指在遍历对象时,使用两个或多个指针(索引、游标)不断进行单向移动来遍历及相应的操作的算法技巧。暴力算法往往可以优化为双指针算法。
双指针的三个关键点:
- 指针的起始位置的选取。可能在同一个序列,也可能在不同序列。
- 指针的移动方向。
- 指针的移动速度。
几种算法模型:
- 对撞指针
- 快慢指针
- 滑动窗口
- 归并排序
2、对撞指针
对撞指针:左右两个指针,向中间靠拢。
例1:二分查找 binarySearch
例2:搜索拼接数组
#一个数组是由两个递增数组首尾拼接的。
#请你在数组中搜索 target ,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。
'''
数组从前到后和从后到前分别为两个有序数组,可以从两端同时查找。'''
例3:翻转列表
left, right = 0, len(s)-1
while left < right:
s[left], s[right] = s[right], s[left]
left += 1; right -= 1
例4:三数之和
#给你一个整数数组 nums ,判断是否存在三元素和为0。
'''
三指针,滑动窗口和对撞指针的组合
对数组排序后,使用for循环i,同时left=i+1和right=len(n)-1分别向左和向右移动,
相遇时结束,即可遍历(i,left,right)'''
def threeSum(nums: List[int]):
if len(nums) < 3: return []
nums, res, n = sorted(nums), [], len(nums)
for i in range(n - 2):
l, r = i+1, n-1
if nums[i] > 0: break #nums[i]<=nums[l]<=nums[r] --> nums[i]<0
if res != [] and res[-1][0] == nums[i]: continue
#if i >= 1 and nums[i] == nums[i - 1]: continue #和上一句等价
while l < r:
if nums[i] + nums[l] + nums[r] == 0:
res.append([nums[i], nums[l], nums[r]])
while l < r-1 and nums[l] == nums[l+1]: l += 1
while r > l+1 and nums[r] == nums[r-1]: r -= 1
if nums[i] + nums[l] + nums[r] > 0: r -= 1
else: l += 1
return res
3、快慢指针
快慢指针:左右两个指针,一块一慢。
例1:找出单链表中间节点(倒数第n个节点)。
例2:判断子序列。
#给定字符串 s 和 t ,判断 s 是否为 t 的子序列。
#字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。
#(例如,"ace"是"abcde"的一个子序列,而"aec"不是)
'''
设置两个指针i,j;i从s的第一个字符开始,j从t的第一个字符开始,当相等时,i和j都右移,
不相等则仅j右移,最后如果i等于s的长度,那么说明完全匹配成功,s是t的子序列。'''
4、滑动窗口
滑动窗口:左右两个指针组成一个"窗口",右指针不断扩张,左指针按条件收缩。
例1:最大连续1的个数。
#给定一个由若干 0 和 1 组成的数组 A,我们最多可以将 K 个值从 0 变成 1 。
#返回仅包含 1 的最长(连续)子数组的长度。
'''
本题求最大连续1的个数,就是在小于等于k个0的基础上求最长符合条件区间的长度。我们使用双指针l r,
代表窗口的两边,从最初开始遍历数组,如果值为1或者此时区间 [l, r] 中0的个数 <= k,
我们就向右移指针r扩大窗口,并更新0的个数,当0的个数大于k,我们就需要更新最大符合条件的区间长度。
然后右移l缩小窗口,更新0的个数,继续重复直至右指针超出数组下标界限,遍历结束,
此时记录最大区间长度的值即为所求。'''
例2:最大区间。
#给定一个长度为 n 的整数序列,请找出最长的不包含重复的数的连续区间,输出它的长度。
def longest(lst):
m= i= j= 0; l=len(lst); d=set() #集合和指针全局声明,新一轮可以参考上一轮遍历进度
while i<l:
if lst[i] in d: #如果新的不在上一轮集合里面,则长度不会超上一轮长度,跳过
d=set(); j=i #重置集合和左指针
else:
d.add(lst[i])
while j>=0: #从上一轮最长长度处开始遍历。
if lst[j] not in d:
d.add(lst[j]); j-=1
else:
m=max(m,i-j)
break
i += 1
return m
5、归并排序
例: 合并两个有序数组。
def merge(nums1,nums2):
sort = []
p1 = p2 = 0 ; m,n = len(nums1),len(nums2)
while p1 < m or p2 < n:
if p1 == m:
sort.append(nums2[p2])
p2 += 1
elif p2 == n:
sort.append(nums1[p1])
p1 += 1
elif nums1[p1] < nums2[p2]:
sort.append(nums1[p1])
p1 += 1
else:
sort.append(nums2[p2])
p2 += 1
return sort
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)