同向双指针(滑动窗口)

同向双指针

  • 1、长度最小的子数组
    • [1.1 题目描述](#1.1 题目描述)
    • [1.2 解答思路](#1.2 解答思路)
  • [2、乘积小于 k 的子数组](#2、乘积小于 k 的子数组)
    • [2.1 题目描述](#2.1 题目描述)
    • [2.2 解答思路](#2.2 解答思路)

1、长度最小的子数组

1.1 题目描述

1.2 解答思路

如果采用暴力做法,枚举子数组的左端点,不断扩展右端点,直至满足条件,那么这样做的时间复杂度是 O( n 2 n^2 n2),显然是需要优化的。

再次审题可以发现还有个条件未使用到,那就是数组的元素都是正整数 。如果子数组的总和大于等于 target,那么右端点右移,即再加上一个正整数,该子数组的总和也一定满足条件,但是题目要求寻找满足条件的长度最小的子数组,因此我们可以保持右端点不动,将左端点右移,直至不满足条件,这样就可以找到右端点所在的子数组的最小长度;不断重复上述过程,直至右端点遍历到最后一个元素。

由上述分析可得,我们可以利用相向双指针,右指针指向子数组的右端点,左指针指向子数组的左端点;右指针不断右移,扩展子数组的元素,直至元素和大于等于 target,此时就可以判断是否可以右移左指针使得元素和大于等于 target的同时减小数组长度。

python 复制代码
class Solution:
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        left = 0
        s = 0
        n = len(nums)
        ans = n+1
        # 循环遍历右端点
        for right, x in enumerate(nums):
            # 扩展右端点
            s += nums[right]
            # 以 nums[right] 为右端点的数组在满足条件的情况下,不断缩小左端点来找到长度最小的子数组
            while s>=target:
                ans = min(ans, right-left+1)
                s = s-nums[left]
                left += 1
            
        return ans if ans!=n+1 else 0

可知,上述算法的时间复杂度是 O(n),空间复杂度是 O(1)。

思路分析:

这道题的主要思想是"枚举右端点,收缩左端点",虽然这里用到了一个 for 循环和一个 while 循环,但是时间复杂度可以理解为 left +1 的次数,也就是 O(n)。

2、乘积小于 k 的子数组

2.1 题目描述

2.2 解答思路

由题目可知,数组元素的范围是 [1, 1000],因此乘以一个元素的乘积一定会变大,那么当我们多乘以一个元素,如果乘积大于等于 k 的话,我们就需要缩减子数组的个数,直至满足条件。

根据上述分析,我们可以设置左右指针分别指向子数组的左右端点:

  • 当子数组的乘积小于 k 时,那么符合条件的子数组的个数是 r-l+1,此时符合子数组有 [l...r],[l+1...r], ..., [r...r],因此我们只需要遍历右指针,从而计算右端点固定的满足条件的子数组的个数即可;
  • 当子数组的乘积大于 k 时,左指针不断右移,缩小数组的元素个数从而减少子数组乘积,也就是从不满足条件变换为满足条件。
python 复制代码
class Solution:
    def numSubarrayProductLessThanK(self, nums: List[int], k: int) -> int:
        cnt = 0
        left = 0
        pro = 1
        # 提示中说明数组元素>=1,因此如果 K<=1,那么数组任何元素都不满足,返回0
        if k<=1:
            return 0
        # 枚举右端点
        for right, x in enumerate(nums):
            pro *= x
            # 注意:这里不需要判断 left <= right,因为如果 left>right,那么pro=1,自然跳出循环
            while pro >= k:
                pro /= nums[left]
                left += 1
            # x 为右端点的满足条件的子数组的个数是 right-left+1
            # 注意:如果left>right从而跳出循环的话,right-left+1=0
            cnt += right-left+1
            
        return cnt

可知,上述算法的时间复杂度是 O(n),空间复杂度是 O(1)。

思路分析:

这道题的主要思想仍然是"枚举右端点,收缩左端点",不过和上题相比,这道题的 while 循环是从不满足条件变换到满足条件。

相关推荐
Cha0DD4 小时前
【由浅入深探究langchain】第二十集-SQL Agent+Human-in-the-loop
人工智能·python·ai·langchain
Cha0DD5 小时前
【由浅入深探究langchain】第十九集-官方的SQL Agent示例
人工智能·python·ai·langchain
阿豪学编程6 小时前
LeetCode724.:寻找数组的中心下标
算法·leetcode
智算菩萨6 小时前
【Tkinter】4 Tkinter Entry 输入框控件深度解析:数据验证、密码输入与现代表单设计实战
python·ui·tkinter·数据验证·entry·输入框
墨韵流芳6 小时前
CCF-CSP第41次认证第三题——进程通信
c++·人工智能·算法·机器学习·csp·ccf
七夜zippoe6 小时前
可解释AI:构建可信的机器学习系统——反事实解释与概念激活实战
人工智能·python·机器学习·可解释性·概念激活
csdn_aspnet7 小时前
C# 求n边凸多边形的对角线数量(Find number of diagonals in n sided convex polygon)
开发语言·算法·c#
凌波粒7 小时前
LeetCode--349.两个数组的交集(哈希表)
java·算法·leetcode·散列表
paeamecium8 小时前
【PAT甲级真题】- Student List for Course (25)
数据结构·c++·算法·list·pat考试
Book思议-8 小时前
【数据结构】栈与队列全方位对比 + C 语言完整实现
c语言·数据结构·算法··队列