双指针算法
顾名思义,即两个指针解决一道题。
当然也可以也可以三个指针,四个指针,但是指针过多容易把自己绕晕。
分类
双指针分类:
- 普通双指针:两个指针相同往同一个方向移动
- 对撞双指针:两个指针面对面移动
- 快慢双指针:满指针+快指针
例题
例题1
假如给定一个有序数组[1,4,5,7,9]
,其中的数字单调递增,并且没有重复的数字。从其中取两个不同的数,使两数和为12
,问可以找到几组这样的数
解法1:普通双指针
枚举,复杂度O(n^2)
a = [1,4,5,7,9]
cnt = 0
for i in range(len(a)):
for j in range(i+1, len(a)):d
if a[i]+a[j] == 12:
cnt += 1
解法2:对撞双指针
适用于数据有单调性的情况,复杂度O(n)
a = [1,4,5,7,9]
cnt = 0
i=0
j=len(a)-1
while(1):
if i>j:
break
if a[i]+a[j]==12:
print(i, j)
break
elif a[i]+a[j]<12:
i += 1
else:
j -= 1
例题2
给定一个链表,如何判断链表内有环
解法1:快慢双指针
# 指针i每往前移动一步,指针j就往前移动两步,如果i和j相遇,说明链表内有环
习题
leetcode 141. 环形链表
给你一个链表的头节点 head
,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next
指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos
不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true
。 否则,返回 false
。
解法:快慢指针
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def hasCycle(self, head: Optional[ListNode]) -> bool:
# 如果链表长度小于等于1,不可能成环
if not head or not head.next:
return False
i = j = head
while 1:
# 循环跳出条件
if(i==None or j==None or j.next==None): # 这里判断j.next是防止j后移过程中报错
return False
i = i.next
j = j.next.next
if(i == j):
return True
leetcode 881. 救生艇
给定数组 people
。people[i]
表示第 i
个人的体重 ,船的数量不限,每艘船可以承载的最大重量为 limit
。
每艘船最多可同时载两人,但条件是这些人的重量之和最多为 limit
。
返回 承载所有人所需的最小船数 。
解法:对撞双指针
class Solution:
def numRescueBoats(self, people: List[int], limit: int) -> int:
people = sorted(people)
i = 0
j = len(people)-1
cnt = 0
while(1):
if j < i:
break
if people[i]+people[j]<=limit:
i += 1
j -= 1
cnt += 1
else:
j -= 1
cnt += 1
return cnt