双指针的原理与题单

原理

双指针,本质上是从$O(n^2)$的搜索空间中排除掉不可能的范围,缩减到$O(n)$的复杂度。

参考:167. 两数之和 II - 输入有序数组 - 力扣(LeetCode)

例题

2824. 统计和小于目标的下标对数目 - 力扣(LeetCode)

这一题中,我们既可以让i每次循环加1,j随之变化;也可以让j每次循环减1,i随之变化。

第一种思路:i每次循环加1,j随之变化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution:
def countPairs(self, nums: List[int], target: int) -> int:
nums.sort()
j = len(nums) - 1
ans = 0
# 遍历第一个指针,寻找满足k>i且nums[i]+nums[k]<target的k
for i in range(len(nums) - 1):
# 1.由于nums是递增的,如果nums[i] + nums[i + 1] >= target,
# 后面都不会存在满足条件的k了,跳出循环;
# 2.如果i==j,上个循环结束i=j-1且nums[i]+nums[j]<target,
# nums[i]+nums[j+1]>=target,所以nums[j]+nums[j+1]>=target,后面不存在满足条件的k;
# i>j时说明上个循环就不存在满足条件的k了
if nums[i] + nums[i + 1] >= target or i >= j:
break
# 我们要让j随着i变化,j是递减的,随着j的递减,nums[i] + nums[j]会变小,
# 所以当nums[i] + nums[j]>=target时要一直循环,
# 保证可以找到nums[i] + nums[j] < target的临界点,这样所有小于等于j大于i的下标都满足条件
while i < j and nums[i] + nums[j] >= target:
j -= 1
ans += j - i
return ans
第二种思路:j每次循环减1,i随之变化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution:
def countPairs(self, nums: List[int], target: int) -> int:
nums.sort()
i = 0
ans = 0
# 遍历第二个指针,寻找满足k<j且nums[k]+nums[j]<target的k
for j in range(len(nums) - 1, 0, -1):
# 1.这里不会有提前退出的机制,因为j是循环递减的,nums[j]也是循环递减的,
# 因此循环次数越多,越容易找到满足条件的i
# 2.如果i>=j,说明所有小于j的下标都是满足要求的,不能退出,此时满足条件的下标一共i个

# 我们要让i随着j变化,i是递增的,随着i的递减,nums[i] + nums[j]会变大,
# 所以当nums[i] + nums[j]<target时要一直循环,
# 保证可以找到nums[i] + nums[j] >= target的临界点,这样所有小于i的下标都满足条件
while i < j and nums[i] + nums[j] < target:
i += 1
# i>=j和i<j的情况合并之后,ans+=min(i,j)
ans += min(i, j)
return ans

另外,如果求的是$abs(nums[i]-nums[j])$大于或者小于target的数量,初始时要设置为i=0,j=1i=len(nums)-2,j=len(nums)-1

双指针题单:

167. 两数之和 II - 输入有序数组 - 力扣(LeetCode)

15. 三数之和 - 力扣(LeetCode)

18. 四数之和 - 力扣(LeetCode)

611. 有效三角形的个数 - 力扣(LeetCode)

16. 最接近的三数之和 - 力扣(LeetCode)

2824. 统计和小于目标的下标对数目 - 力扣(LeetCode)

缩减搜索范围题单:

240. 搜索二维矩阵 II - 力扣(LeetCode)

11. 盛最多水的容器 - 力扣(LeetCode)

更新于 阅读次数