双指针

双指针

双指针包括快慢指针和反向指针;

快慢指针:快指针走在前面,慢指针走在后面;快指针用于遍历,慢指针用于和快指针指向的对象进行对比,当满足条件时慢指针才向前移动

反向指针:一个指针指向数组的头,另一个指向数组尾,两个指针交替前进,当满足某个条件时停下来,接着继续前进,直到两个指针相遇,算法结束

滑动窗口https://blog.csdn.net/u010569893/article/details/105266952 实际上也是双指针的应用,滑动窗口的右指针不断扩大窗口的范围,当窗口内的对象符合某个条件时,进行统计或者某种操作;然后左指针收缩窗口来打破条件,让右指针继续扩大窗口;这里滑动窗口的题目就不再展开了

  1. 392. 判断子序列

    给定字符串 st ,判断 s 是否为 t 的子序列。

    思路:使用快慢指针;

    快指针指向长字符串t,快指针不断前移;

    慢指针指向短字符串s, 当慢指针的字符 跟快指针的字符 相同时,慢指针前移;

    当慢指针在快指针之前或者同时遍历完字符串时,返回True; 否者返回False

class Solution:
    def isSubsequence(self, s: str, t: str) -> bool:
        if not s:
            return True         
        i, j = 0, 0 # i:慢指针,j:快指针
        while j<len(t):
            c = t[j]
            if s[i] == c:             
                if i == len(s)-1:
                    return True 
                i += 1
            j+=1  
        return False

2.两个数组的交集

给定两个数组,编写一个函数来计算它们的交集

思路:使用快慢指针;

快指针指向长字符串t,快指针不断前移;

慢指针指向短字符串s, 当快指针指向的字符在短字符串中时,慢指针前移;

当慢指针在快指针之前或者同时遍历完字符串时,返回True; 否者返回False

class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
        if not nums1 or not nums2:
            return []
        nums1 = list(set(nums1))
        nums2 = list(set(nums2))
        res = []
        #nums1:短数组;nums2:长数组
        if len(nums1) > len(nums2):
            nums1, nums2 = nums2, nums1 
        i, j = 0, 0 # i:慢指针指向短数组, j:快指针,指向长数组
        while j < len(nums2):
            num = nums2[j]
            if num in nums1:
                res.append(num)
                if i == len(nums1)-1:
                    break
                i+=1
            j+=1
        return res
  1. 三数之和的多种可能

    给定一个整数数组 A,以及一个整数 target 作为目标值,返回满足 i < j < k 且 A[i] + A[j] + A[k] == target 的元组 i, j, k 的数量。

    由于结果会非常大,请返回 结果除以 10^9 + 7 的余数。

    思路:首先将数组排序;

    使用三个指针,第一个指针i用于遍历数组,第二个指针j(左指针)指向i后的第一个元素,第三个指针j(右指针)执行i后的最后一个元素

    当j和k指向的元素之和大于target时,k左移;小于target时,j右移;当元素之和等于target时,进行统计;

    由于数组中可能存在重复元素,根据数学组合公式,来进行计算

    当左指针和右指针相遇时,某次遍历结束,进行下一次遍历

    class Solution:
        def threeSumMulti(self, A: List[int], target: int) -> int:
        
            MOD = 10**9 + 7
            ans = 0
            A.sort()
    
            for i, x in enumerate(A):
                T = target - A[i]
                j, k = i+1, len(A) - 1
    
                while j < k:
                    if A[j] + A[k] < T:
                        j += 1
                    elif A[j] + A[k] > T:
                        k -= 1
                    elif A[j] != A[k]: # We have A[j] + A[k] == T.
                        left = right = 1
                        while j + 1 < k and A[j] == A[j+1]:
                            left += 1
                            j += 1
                        while k - 1 > j and A[k] == A[k-1]:
                            right += 1
                            k -= 1
                        ans += left * right
                        ans %= MOD
                        j += 1
                        k -= 1
    
                    else:
                        # M = k - j + 1
                        # We contributed M * (M-1) / 2 pairs.
                        ans += (k-j+1) * (k-j) / 2
                        ans %= MOD
                        break
    
    1. 颜色分类

      给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。

      此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。

      思路:使用三个指针;第一个指针curr进行遍历, 第二个指针p0(左指针)指向最左边, 第三个指针p2(右指针)指向最右边;

      当curr指向的当前数=2时,将当前数跟右指针指向的元素互换,然后右指针左移一位;

      当当前数=0时,将0跟左指针指向的元素互换,然后左指针右移一位;curr继续左移

      当当前数=1时,不做处理,curr继续左移

      class Solution:
          def sortColors(self, nums: List[int]) -> None:
              """
              Do not return anything, modify nums in-place instead.
              """
              if len(nums)<=1:
                  return 
              p0=curr=0 #p0:0的起始位置 curr:当前指针
      
              p2 = len(nums)-1 #2的起始位置
              while curr<=p2:
                  if nums[curr]==0:
                      nums[curr],nums[p0] = nums[p0], nums[curr]
                      curr+=1
                      p0+=1
      
                  elif nums[curr]==2:
                      nums[curr], nums[p2] = nums[p2], nums[curr]
                      p2-=1
      
                  elif nums[curr]==1:
                      curr+=1
      
    2. 80. 删除排序数组中的重复项 II

      思路:快指针用于遍历,慢指针用于更新数组

      class Solution:
          def removeDuplicates(self, nums: List[int]) -> int:
              if len(nums)<=2:
                  return len(nums)
              count = 0
              i, j = 1, 1 # 快、慢指针
              while i<len(nums):
                  if nums[i]==nums[i-1]:
                      count+=1
                      if count<=1:
                          nums[j] = nums[i]
                          j+=1
                      i+=1
                  else:
                      nums[j] = nums[i]
                      j+=1
                      i+=1
                      count = 0 
      
              return len(nums[:j])
      
    3. 寻找重复数

      思路:根据鸽巢原理(抽屉原理),当存在重复数时,必定有一个数字的个数大于1

      暴力方法:从1-n依次统计每个数出现的次数,当某个数出现的次数大于1时,该数就是重复数

      我们知道该数组中是一个1-n是有序数组,可以用二分法来统计,左指针指向1,右指针指向n

      class Solution:
          def findDuplicate(self, nums: List[int]) -> int:
              size = len(nums)-1
              l = 1
              r = size 
              while l<r:
                  m = (l+r)//2
                  cnt = 0
                  for num in nums:
                      if num <= m:
                          cnt +=1 
                  if cnt > m:
                      r = m 
                  else:
                      l = m+1 
              return l
      
    4. 344. 反转字符串
      class Solution:
          def reverseString(self, s: List[str]) -> None:
              """
              Do not return anything, modify s in-place instead.
              """
              if len(s)<=1:
                  return 
              l = 0
              r = len(s)-1
              while l<r:
                  s[l], s[r] = s[r], s[l]
                  l+=1
                  r-=1
      
    5. 567. 字符串的排列

      思路:使用i和j来构造一个滑动窗口,其中i用于遍历,j用于构造一个长度为len(s1)的滑动窗口

      遍历s2,当有字符在s1中时,比较排序后的滑动窗口内的字符串是否跟排序后的s1相同,相同的话,返回True,反之继续遍历

      class Solution:
          def checkInclusion(self, s1: str, s2: str) -> bool:
              s1 = sorted(s1)
              for i in range(len(s2)):
                  if s2[i] not in s1:
                      continue 
                  j = i+len(s1)-1
                  if j > len(s2)-1:
                      return False
                  else:
                      sub_s2 = sorted(s2[i:j+1])
                      if sub_s2 == s1:
                          return True 
              return False
      
    6. 167. 两数之和 II - 输入有序数组

      思路:反向指针,当两数之和==target时,返回下标;当>target,右指针左移;当<target,左指针右移

      class Solution:
          def twoSum(self, numbers: List[int], target: int) -> List[int]:
              nums = numbers
              l = 0
              r = len(nums)-1
              while l<r:
                  s = nums[l]+nums[r]
                  if s== target:
                      return l+1,r+1
                  elif target>s:
                      l+=1
                  elif target<s:
                      r-=1
      
    7. 141. 环形链表

      思路:使用快慢指针,当存在环时,快指针永远不会走到尽头,慢指针总会追上快指针;反之,当快指针走到尽头时,慢指针追不上快指针

      # Definition for singly-linked list.
      # class ListNode:
      #     def __init__(self, x):
      #         self.val = x
      #         self.next = None
      
      class Solution:
          def hasCycle(self, head: ListNode) -> bool:
              if not head:
                  return False 
              slow = fast = head 
              while fast and fast.next:
                  slow = slow.next 
                  fast = fast.next.next 
                  if slow == fast:
                      return True 
                      break 
              return False
      
    8. 259. 较小的三数之和

      思路:使用3指针,一个指针用于遍历,另外两个是左右指针

      class Solution:
          def threeSumSmaller(self, nums: List[int], target: int) -> int:
              if len(nums) < 3:  # 处理边界条件
                  return 0
              nums.sort()
              ans = 0
              for i in range(len(nums) - 2):  # 注意i,j,k三个指针不能重合
                  left = i + 1
                  right = len(nums) - 1
                  while left < right:
                      # 如果left和right之和小于target-nums[i],left右移
                      if nums[left] + nums[right] < target - nums[i]:
                          ans += right - left
                          left += 1 
                      # 如果left和right之和大于target-nums[i],right左移
                      else:
                          right -= 1
              return ans
      
      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值