双指针技巧在处理数组和链表相关问题时经常用到,主要分为两类:左右指针和快慢指针。
所谓左右指针,就是两个指针相向而行或者相背而行;而所谓快慢指针,就是两个指针同向而行,一快一慢。
在数组中并没有真正意义上的指针,但我们可以把索引当做数组中的指针,这样也可以在数组中施展双指针技巧,本文主要讲数组相关的双指针算法。
一、快慢指针技巧
在学习这个技巧之前,我就刷了这道题,我的思路是让两个指针一前一后的遍历数组,如果指针内容相同,就删除掉下标小的元素,让后面的指针指向刚刚删除的位置,然后另一个指针是该位置+1,每次删除都要把数组长度减一。
class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
i = 0
j = 1
length = len(nums)
while j <= length - 1 and i < j:
if nums[i] == nums[j]:
nums.pop(i)
i = j - 1
j = i + 1
length -= 1
else:
j += 1
i += 1
return len(nums)
然后使用快慢指针技巧,再试一次:
class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
fast = 0
slow = 0
while fast<len(nums):
if nums[slow] != nums[fast]:
slow += 1
nums[slow] = nums[fast]
else:
fast += 1
return slow+1
class Solution:
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
fast = head
slow = head
while fast:
if fast.val != slow.val:
slow = slow.next
slow.val = fast.val
else:
fast = fast.next
if slow: #保证链表不是空
slow.next = None
return head
在没有学习快慢指针之前,我已经刷了这道题,找python中remove函数,可以原地删除某个值,有点走后门的感觉。
class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
length = len(nums)
i = 0
while i <= length-1:
if nums[i] == val:
nums.remove(val)
length -=1
else:
i += 1
return len(nums)
重新用快慢指针来一次:
class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
fast = 0
slow = 0
while fast<len(nums):
if nums[fast] != val: #没有遇到的时候,先赋值,再给s加一
nums[slow] = nums[fast]
slow += 1
fast += 1#遇到该值时,直接跳过
return slow
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
fast = 0
slow = 0
count = 0
while fast < len(nums): #当fast所指的内容不是0时,赋值给slow,并且将slow向前移动,记下0的个数。fast是0时,直接跳过
if nums[fast] != 0:
nums[slow] = nums[fast]
slow += 1
if nums[fast] == 0:
count += 1
fast += 1
while slow < len(nums):#将slow下标之后的值全部赋值成0
nums[slow] = 0
slow += 1
二、左右指针的常用技巧
只要数组有序,就应该想到双指针技巧。这道题的解法有点类似二分查找,通过调节left
和right
就可以调整sum
的大小:
class Solution:
def twoSum(self, numbers: List[int], target: int) -> List[int]:
right = len(numbers)-1
left = 0
while left != right:
if numbers[left] + numbers[right] == target:
return [left+1,right+1]
elif numbers[left] + numbers[right] < target:
left += 1
else:
right -= 1
return [0,0]
class Solution:
def reverseString(self, s: List[str]) -> None:
right = len(s) - 1
left = 0
while right>left :
t = s[left]
s[left] = s[right]
s[right] = t
right -= 1
left += 1
class Solution:
def isPalindrome(self, s: str) -> bool:
import string
s1 = []
s = s.lower() #将全部字母改成小写字母(s.upper()是改成大写字母)
for i in s:
if i.isalpha() or i.isdigit(): #如果i是字母或者数字则加入数组中
s1.append(i)
left = 0
right = len(s1) -1
while right > left:
if s1[right] == s1[left]:
left += 1
right -= 1
else:
return False
return True
class Solution:
def palindrome(self,s,left,right): #返回以l,r为中心的回文串
while left >= 0 and right < len(s) and s[left] == s[right]:
left -= 1
right +=1
return s[left+1:right]
def longestPalindrome(self, s: str) -> str:
length = len(s)
sub = ''
for i in range(length):
s1 = self.palindrome(s,i,i)
s2 = self.palindrome(s,i,i+1)
sub = s1 if len(sub) < len(s1) else sub
sub = s2 if len(sub) < len(s2) else sub
return sub