双指针法
双指针法三类
- 左右双指针算法
- 快慢双指针算法
- 后序双指针算法
左右双指针算法
左右双指针算法基本思想
左右双指针算法在解决问题的过程中会生成两个指针,一个指向头部,一个指向尾部,从两端向中间逼近,直到满足条件或者两个指针相遇为止. 二分查找就是一种左右双指针算法的应用场景,其他使用情况基本上可以总结为数组中元素组合问题。
经典例题:三数之和
- 该问题是采用左右双指针算法解决的经典问题之一,以三数之和为限制条件,适当调整左右指针。
def threeSum(array):
"""左右双指针"""
array.sort()
res=[]
for k in range(len(array)-2):
if array[k] >0:break
#先固定一个数,若这个数与上个数重复,则去重
if k>0 and array[k] == array[k-1]:continue
"""l指向前节点、r指向尾节点"""
l,r=k+1,len(array)-1
while l<r:
s=array[k]+array[l]+array[r]
if s<0:
#指向前节点的指针向右移
l+=1
#对重复的元素去重,并且向右移
while l<r and array[l]==array[l-1]:l+=1
elif s>0:
#指向尾节点的指针向左移
r-=1
while l<r and array[r]==array[r+1]:r-=1
else:
#若s=0,则构造可行解
res.append([array[k],array[l],array[r]])
l+=1
r-=1
#元素去重
while l<r and array[l]==array[l-1]:l+=1
while l<r and array[r]==array[r+1]:r-=1
return res
快慢双指针法
快慢双指针思想
快慢双指针在解决问题的过程中会使用两个指针,两个指针的起始位置相同,但是在遍历过程中前景速度不同,如慢指针一次前进一步,块指针一次前进两步,通过这样的方式达到目的。快慢双指针算法一般的适用情况有:链表求环、链表求中点、数组中元素替换与查找等问题
经典例题:链表求环
class Solution:
def hasCycle(self, head: ListNode) -> bool:
#考虑特殊情况
if head is None:
return
#快慢双指针初始化
fast=head
slow=head
while(fast):
#如果fast指针指向None,说明无环
if fast.next== None:
return False
#fast每次移动两步、slow每次移动一步
fast=fast.next.next
slow=slow.next
#如果fast==slow,说明快指针追上了慢指针,说明有环
if fast == slow:
return True
经典例题二:回文链表
解题思路
解决这个问题,我们需要考虑两点:
- 寻找原始链表的中间节点
- 对后半部分链表做反转
最终如果后半部分反转的链表与前半部分链表完全一致,说明该链表是回文链表!
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
#考虑特殊情况
if head == None or head.next == None:
return True
#指针初始化
fast=head
slow=head
#寻找中间节点
while (fast.next!=None) and (fast.next.next!=None):
fast=fast.next.next
slow=slow.next
#不论head链表是偶数还是奇数 slow都是中间节点,因此反转后半部分节点传递slow.next
def reverselink(head):
#head表示当前节点、current表示当前节点的下一个节点、pre表示当前节点的上一个节点
#该函数返回反转链表的头指针
current=None
pre=None
while(head!=None):
#链表反转四步骤
current=head.next
head.next=pre
pre=head
head=current
return pre
start=reverselink(slow.next)
#对比反转链表与前半部分链表的个节点是否相同
while(start):
if(start.val != head.val ):
return False
start=start.next
head=head.next
return True
两个数组的交集
解题思路
- 先对两数组进行排序,创建两个指针,起始为零。遍历两数组,当一个数组值小于另外一个数组时,让该数组的指针右移;当一个数组值等于另外一个数组值时,让两个数组的指针右移;直到有一个指针超出了数组长度,跳出循环。
class Solution:
def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]:
nums1.sort()
nums2.sort()
#初始化参数
n1,n2=len(nums1),len(nums2)
res=[]
index1=index2=0
while index1<n1 and index2<n2:
if nums1[index1]<nums2[index2]:
index1+=1
elif nums1[index1]>nums2[index2]:
index2+=1
else:
res.append(nums1[index1])
index1+=1
index2+=1
return res
奇偶排序
解题思路:
- 开辟一个新的空间,将偶数部分存储到A[0]、A[2]、A[4]……将奇数部分存储到A[1]、A[3]、A[5]……
class Solution:
def sortArrayByParityII(self, A: List[int]) -> List[int]:
#两次遍历 将奇数存到 a[1]、a[3]……
n=len(A)
alist=[None]*n
t=0
for i in A:
if i%2==0:
alist[t]=i
t+=2
t=1
for i in A:
if i%2==1:
alist[t]=i
t+=2
return alist
删除链表的倒数第几个元素
class Solution:
def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
# 创建一个哑节点,这样一来就无需对头节点进行判断
dummy = ListNode(0)
dummy.next = head
# 1. 快指针先走
fast = slow = dummy
for i in range(n):
fast = fast.next
# 2. 快慢指针一起走
while fast.next:
fast,slow = fast.next,slow.next
# 3. 让慢指针next指向下一个节点
slow.next =slow.next.next
return dummy.next