关于尺取(双指针)法的理解
(以下某些符号以Python语言为主。本文是个人的理解,若有错误,还望指正!)
以下关于该方法的理解是出自我在写相关程序的时候遇到的超出所设置时间范围的问题的一个解法。该解法在针对某些特定问题的时候可以减少时间成本,即降低时间复杂度。
在某些问题中例如:给定一个列表A = [a,b,c,d,e,f] ,求出一个目标值 t,该目标值 t 需要从给定的列表中找出三个数相加得到。三个数只能从列表中找,并且某数的重复次数不得超过列表中出现的该数的次数。
有种解决方案是使用循环搜索:
for i in A:
...
XXX
for e in A:
...
XXX
for v in A:
...
XXX
XXX
...
但是这种方法的时间复杂度过高,达到O(n^3),因此最好不要选择这种解决方案。这个时候可以选择尺取法。
那么尺取法的思路是:
首先给列表排序。在排序结束之后,固定第一个值a(其元素假设为 i,一般刚开始它是列表第一个元素),随后再固定两个值,分别是b(假设下标为 left,一般刚开始它是列表第二个元素),与c(假设下标为 right,一般刚开始它是A列表的最后一个元素)。
然后开始进行计算:
S = A[i] + A[left] + A[right]
计算S与 t 是否相等,如果相等,直接
return S
如果不等,就要判断S与 t 的关系:
若 S > t,表明我们三个数相加得到的结果大于目标值,此时不用再将 left 往右移动 1 位,即不用再遍历 left 往后移动的情况。因为列表已经排序,所以即使再往后移动,三数相加结果也必然大于目标值 t 。下面需要做的就是将我们指定的下标为right的数向左移动 1 位,使得三数相加的和降低。然后循环,直到找出目标值 t 。在循环过程中,一般会出现 left 遍历一遍之后,仍没有找到 S = t,那么下面是将 i 的下标往右移动一位继续遍历。
若S < t,与上面的思想一样,将指定的下标为left的数向右移动 1 位即可,然后循环,直到找出 t 。
另外附上Python代码。这个代码是寻找三个数之和中与目标值最接近的,其解决方案和上述思想一致。
(还在学习中,程序写的着实不好,见谅…)
A 是指定列表,t 是目标值。
class Solution(object):
def ClosestSum(self,A,t):
A.sort()
res = []
for i in range(len(A)):
left = i + 1
right = len(A) - 1
if right <= left:
break
for v in range(len(A)):
Sum = A[i] + A[left] + A[right]
res.append(Sum)
if Sum > t:
right -= 1
if right == left:
break
elif Sum < t:
left += 1
if left == right:
break
else:
return Sum
abs_res = [abs(t - i) for i in res]
S = min(abs_res)
return res[abs_res.index(S)]
if __name__ == '__main__':
A = Solution()
B = A.ClosestSum([2,4,8,16,32,64,128],82)
print(B)