Leetcode刷题——数组双指针

本文概述了如何利用双指针技巧解决LeetCode中的问题,如移动零、颜色分类、合并有序数组等。重点介绍了滑动窗口的概念及其在算法中的应用,如字符串反转、三数之和和重复元素检测。通过实例演示,提升数组和字符串操作的效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Leetcode刷题——数组双指针

内容概要

双指针(Two Pointers):指的是在遍历元素的过程中,不是使用单个指针进行访问,而是使用两个指针进行访问,从而达到相应的目的。如果两个指针方向相反,则称为「对撞时针」。如果两个指针方向相同,则称为「快慢指针」。如果两个指针分别属于不同的数组 / 链表,则称为「分离双指针」。

滑动窗口(Sliding Window):在给定数组 / 字符串上维护一个固定长度或不定长度的窗口。可以对窗口进行滑动操作、缩放操作,以及维护最优解操作。滑动操作——窗口可按照一定方向进行移动。最常见的是向右侧移动。缩放操作——对于不定长度的窗口,可以从左侧缩小窗口长度,也可以从右侧增大窗口长度。
滑动窗口利用了双指针中的快慢指针技巧,我们可以将滑动窗口看做是快慢指针两个指针中间的区间,也可以可以将滑动窗口看做是快慢指针的一种特殊形式。

刷题

    1. 移动零
class Solution:
    def moveZeroes(self, nums: List[int]) -> None:
        left = 0
        right = 0
        while right < len(nums):
            if nums[right] != 0:
                nums[left],nums[right] = nums[right],nums[left]
                left += 1
            right  += 1
    1. 颜⾊分类
      对数组 nums 里面的每一个值 nums[i] 进行遍历,如果 nums[i] == 0 就放到前面,如果 nums[i] == 2 就放到后面,顺序就排好了。具体的操作中可以用两个指针 p0 和 p2 分别来标识 0 的下一位和2的上一位,p0 从0开始往后,p2 从 n-1 开始往前。
class Solution:
    def sortColors(self, nums: List[int]) -> None:
        left = 0
        right = len(nums)-1
        i = 0
        
        while i <= right:
        #nums[i] 和 nums[p2] 交换,nums[p2] 还没有被check过,交换后,nums[p2] 被交换到 nums[i] 的位置后,如果 i 移动到 i+1, 那么 nums[p2] 就被漏掉了。所以,要继续比较 nums[i] 是否等于 0 或 2。
            while nums[i] == 2 and i <= right:
                nums[i],nums[right] = nums[right],nums[i]
                right -= 1
            if nums[i] == 0:
                nums[i],nums[left] = nums[left],nums[i]
                left += 1
            i += 1
        return nums

    1. 合并两个有序数组
class Solution:
    def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
        """
        Do not return anything, modify nums1 in-place instead.
        """
        #l为nums1的m开始索引, r为nums2的n开始索引,index为修改nums1的开始索引,然后从nums1末尾开始往前遍历
        l, r, index = m - 1, n - 1, len(nums1) - 1      
        #按从大到小,从后往前修改nums1的值,每次都赋值为nums1和nums2的当前索引的较大值,然后移动索引
        while l >= 0 and r >= 0:
            #如果nums1[l] >= nums2[r],则先赋值为nums1[l],l索引减少
            if nums1[l] >= nums2[r]:
                nums1[index] = nums1[l]
                l -= 1
            else:
                #如果nums1[l] <= nums2[r],则先赋值为nums2[r],r索引减少
                nums1[index] = nums2[r]
                r -= 1
            #当前nums1修改索引减少1
            index -= 1
        #nums2没有遍历完n个,则继续遍历,直到n个完成
        while r >= 0:
            nums1[index] = nums2[r]
            r -= 1
            index -= 1  
    1. 反转字符串
class Solution:
    def reverseString(self, s: List[str]) -> None:
        n = len(s)
        for i in range(n//2):
            s[i], s[n-1-i] = s[n-1-i], s[i]
    1. 三数之和
class Solution:
    def threeSum(self, nums: [int]) -> [[int]]:
        nums.sort()
        res, k = [], 0
        for k in range(len(nums) - 2):
            if nums[k] > 0: break # 1. because of j > i > k.
            if k > 0 and nums[k] == nums[k - 1]: continue # 2. skip the same `nums[k]`.
            i, j = k + 1, len(nums) - 1
            while i < j: # 3. double pointer
                s = nums[k] + nums[i] + nums[j]
                if s < 0:
                    i += 1
                    while i < j and nums[i] == nums[i - 1]: i += 1
                elif s > 0:
                    j -= 1
                    while i < j and nums[j] == nums[j + 1]: j -= 1
                else:
                    res.append([nums[k], nums[i], nums[j]])
                    i += 1
                    j -= 1
                    while i < j and nums[i] == nums[i - 1]: i += 1
                    while i < j and nums[j] == nums[j + 1]: j -= 1
        return res
    1. 删除有序数组中的重复项 II
class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        if len(nums)<=2:
            return len(nums)
        lens=0
        for n in nums:
            if lens<2 or n>nums[lens-2]:
                nums[lens]=n
                lens=lens+1
        return lens
    1. 最⻓连续递增序列
class Solution:
    def findLengthOfLCIS(self, nums: List[int]) -> int:
        size = len(nums)
        if size == 0:
            return 0
        res = 1
        #记录最长连续递增子序列长度
        count = 1
        #计算当前子序列的递增长度
        for i in range(size - 1):
            if nums[i + 1] > nums[i]:
                count += 1
            else:
                count = 1
            if count > res:
                res = count
        return res
    1. 最⼤连续1的个数 III
class Solution:
    def longestOnes(self, nums: List[int], k: int) -> int:
        res = cnt = l = r = 0
        #缩小窗:包含0超过k时,开始缩小窗使其包含的0不超过k个
        #cnt记录当前包含0的个数
        while r<len(nums):
            if nums[r] == 0:cnt+=1
            #记录已经包含0的个数
            r += 1
            #扩大窗:包含0不超k时,不断右移扩大窗
            while cnt > k:
                if nums[l] == 0:cnt-=1
                l += 1
            res = max(res,r-l)
            #更新结果
        return res
    1. 存在重复元素 III
class Solution:
    def containsNearbyAlmostDuplicate(self, nums: List[int], k: int, t: int) -> bool:
        bucket_dict = dict()
        for i in range(len(nums)):
            # 将 nums[i] 划分到大小为 t + 1 的不同桶中
            num = nums[i] // (t + 1)

            # 桶中已经有元素了
            if num in bucket_dict:
                return True

            # 把 nums[i] 放入桶中
            bucket_dict[num] = nums[i]

            # 判断左侧桶是否满足条件
            if (num - 1) in bucket_dict and abs(bucket_dict[num - 1] - nums[i]) <= t:
                return True
            # 判断右侧桶是否满足条件
            if (num + 1) in bucket_dict and abs(bucket_dict[num + 1] - nums[i]) <= t:
                return True
            # 将 i-k 之前的旧桶清除,因为之前的桶已经不满足条件了
            if i >= k:
                bucket_dict.pop(nums[i-k] // (t + 1))

        return False

参考资料
https://github.com/itcharge
https://leetcode-cn.com/problems/sort-colors/solution/75-yan-se-fen-lei-python-shuang-zhi-zhen-pl1a/
https://leetcode-cn.com/problems/merge-sorted-array/solution/python3-shuang-zhi-zhen-xiu-gai-0mnfu-za-dee5/
https://leetcode-cn.com/problems/3sum/solution/3sumpai-xu-shuang-zhi-zhen-yi-dong-by-jyd/
https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array-ii/solution/xiao-bai-gan-wu-fen-xiang-by-zut_liu-kan-mxgn/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值