剑指 Offer II 009. 乘积小于 K 的子数组

剑指 Offer II 009. 乘积小于 K 的子数组

原题

剑指 Offer II 009. 乘积小于 K 的子数组

解法1: 枚举

最直观的解决方法就是枚举每一个子数组左边界和右边界, 并查看该子数组的乘积是否小于 k。

设子数组的乘积为 product,

设子数组的左边界下标为 i (0 <= i < nums.length), 右边界下标为 j; 开始时 i = j, 也就是该子数组只有一个元素的时候; 此时, product = nums[j]。

  • 当 product < k 时, 说明存在一种子数组, 使得乘积小于 k; ++result
    • 否则, 由于 nums[i] >= 1, 说明往后枚举的子数组乘积是非递减的, 因此停止这次枚举

1.png2.png3.png4.png5.png

具体实现代码如下

 class Solution {
		public int numSubarrayProductLessThanK(int[] nums, int k) {
			int result = 0;
			int product = 1;
			for (int i = 0; i < nums.length; i++) {
				for (int j = i; j < nums.length; j++) {
					product *= nums[j];
					if (product >= k) {
						break;
					}
					++result;
				}
                // 将子数组乘积重置
				product = 1;
			}
			return result;

		}
	}

复杂度分析

  • 时间复杂度:O(n^2), 在最差的情况下, 对于长度为 n 的数组, 接近于嵌套的 for 循环。
    • 空间复杂度:O(1)。

解法二: 滑动窗口

设 left, right 分别作为子数组的两个边界, 乘积 product;

假定长度为 n 的连续子数组满足乘积 < k, 那么 nums[left] ~ nums[right] 的任意子数组都满足乘积 < k。

此时, 子数组个数有: *1 + 2 + 3 + ··· + n-1 + n = (n + 1)n/2 个。

那么当子数组 right 指针增长时, 只会有两种情况

  1. product *= nums[right] < k;

    数组长度变化: n -> n+1

    因此有 (n+2)*(n+1)/2 种子数组组合, 相比于长度 n 时, 增加了 (3n + 2 - n) / 2 = n + 1;

    由此我们可以知道, 当 right 指针右移时, 子数组答案种数增加了 (n + 1)

    n + 1 = right - left + 1 (right, left 为 当前的指针值)

    res += (right - left + 1);
    

    这里需要注意: res 加上了 nums[left] ~ nums[right] 区间内新增的所有的可能

    1. product *= nums[right] >= k;

      我们需要对子数组区间进行缩小, 通过 left++, 将乘积 product 缩小

      product /= nums[left++];
      

      如果 left == right, 说明的单个元素都大于 k, 因此还需要 right++, 同时 product = 1;

代码实现

在代码实现上, 我们先将 left, right 指针重叠, 初始的乘积为 1(确保单个元素的时候, 乘积为本身)

 class Solution {
		public int numSubarrayProductLessThanK(int[] nums, int k) {
			int result = 0;
			int product = 1;
			int left = 0;
			int right = 0;
			while (right < nums.length) {
				if (product * nums[right] < k) {
					product *= nums[right];
					result += (right - left + 1);
					++right;
				} else if (left == right) {
					product = 1;
					++right;
					left = right;
				} else {
					product /= nums[left++];
				}
			}
			return result;

		}
	}

复杂度分析

  • 时间复杂度: O(n), 其中 n 为数组的长度, 只需一次遍历即可得到答案。
    • 空间复杂度: O(1)。

其他

本题解同步至剑指offer专项突击版仓库内, 欢迎查看。

我的力扣主页

Github仓库

Gitee仓库

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值