欢迎光临散文网 会员登陆 & 注册

leetcode刷题笔记:number-of-subarrays-with-bounded-maximum( 动态规划 && 单

2022-11-24 19:54 作者:StepfenShawn  | 我要投稿

题目地址:

https://leetcode.cn/problems/number-of-subarrays-with-bounded-maximum/

题目描述

Given an integer array nums and two integers left and right, return the number of contiguous non-empty subarrays such that the value of the maximum array element in that subarray is in the range [left, right].

The test cases are generated so that the answer will fit in a 32-bit integer.


Example 1:

Input: nums = [2,1,4,3], left = 2, right = 3

Output: 3

Explanation: There are three subarrays that meet the requirements: [2], [2, 1], [3].

Example 2:

Input: nums = [2,9,2,5,6], left = 2, right = 8

Output: 7

题目大概就是要求一个数组的子数组中最大值满足在范围[left, right]的个数。

虽然难度为中等, 但是这题有很多种方法解决,于是写篇博客随便复习一下。

思路1: 动态规划

我们先来证明这个问题是具有子结构的,也就是说我们可以从解决子问题开始最终能得出我们的答案。

我们先来定义子问题,要求数组最终的子数组满足的个数, 我们可以定义 i 表示以 i 作为最后元素中子数组的个数, 于是我们就拆解出了 i 个子问题, 假设这 i 个子问题的解为

(W1%2C%20W2%2C%20...%2C%20Wi)

那么根据题意问题的答案为 %5Csum%5Cnolimits_%7B0%7D%5Ei%20Wi%20 , 即每个以 i 结尾的子数组的个数的和。由子数组的性质可知,每个子问题(W1%2C%20W2%2C%20...%2C%20Wi)都是唯一的, 递归地, %5Csum%5Cnolimits_%7B0%7D%5Ei%20Wi%20也是唯一的,于是我们证明了可以从子问题中推出原问题的解,这个问题是具有子结构的。

一个问题证明了具有子结构后,我们就可以通过递归或递推(动态规划)来解决了,我们先假设出状态:

dp[i][0] : 以 i 作为最后元素中子数组的最大值小于在 [left, right] 中的个数

dp[i][1] : 以 i 作为最后元素中子数组的最大值在 [left, right] 中的个数

已知 nums 里面的元素会出现三种情况:

当 nums[i] >= left 且 nums <= right :  此时 nums[i] 一定会出现在符合的子数组中, 由于符合的子数组中满足 nums[i] 为最大值即可, 那么还可能出现比 nums[i] 小的元素, 并且要求是连续的,所有该子问题的解可以转化为 i - 1 (上一个)状态的解:

我们此时的状态方程可以这样写:

              dp[i][1] = 1 + dp[i - 1][1] + dp[i - 1][0]

当 nums[i] < left : dp[i][0] = dp[i - 1][0] + 1

                            dp[i][1] = dp[i - 1][1]

当 nums[i] > right 时: 这个元素对我们的答案没有如何贡献, 此时dp[i][0] = dp[i][1] = 0

注意到每个状态只与上一个状态有关,我们还可以用滑动数组进行优化(这里就不写惹。。。)

思路2: 单调栈

对于数组里面的每一个元素 nums[i], 我们考虑它对答案的贡献。如果这个 nums[i] 在 [left, right] 范围内, 我们定义 l[i] 为 nums[i] 左边第一个大于 nums[i] 的元素的下标, r[i] 为 nums[i] 右边第一个大于 nums[i] 的元素的下标, 那么已nums[i]为最大值的子数组有 (i - l[i]) * (r[i] - i) 个(相当于组合问题吧。。。), 那么我们对每个 (i - l[i]) * (r[i] - i)   求和就是答案了。

其中 l[i] 和 r[i] 可以通过 单调栈 这种数据结构来计算出来。时间复杂度仅为 O(n)。

思路3: 模拟 + 计数

利用前缀和的思想,我们先计算出 x = 最大值为 right 的子数组的个数, y = 最大值为 left - 1 的子数组的个数, 然后 x - y 就是 最大值范围在 [left, right]的子数组的个数了!


leetcode刷题笔记:number-of-subarrays-with-bounded-maximum( 动态规划 && 单的评论 (共 条)

分享到微博请遵守国家法律