检测相邻递增子数组 II - LeetCode 3350 解题思路与代码解析
在本篇博客中,我们将深入解析一道中等难度的算法题------检测相邻递增子数组 II。通过这道题,我们将学习如何高效地处理数组中的递增子数组问题,并理解解决该问题的最佳策略。
题目描述
给定一个由 n
个整数组成的数组 nums
,请你找出 k
的最大值,使得存在两个相邻且长度为 k
的严格递增子数组。具体来说,需要检查是否存在从下标 a
和 b
(a < b
) 开始的两个子数组,并满足下述全部条件:
- 这两个子数组
nums[a..a + k - 1]
和nums[b..b + k - 1]
都是严格递增的。 - 这两个子数组必须是相邻 的,即
b = a + k
。
子数组是数组中的一个连续非空的元素序列。
示例
示例 1:
输入:nums = [2,5,7,8,9,2,3,4,3,1]
输出:3
解释:
从下标 2 开始的子数组是 [7, 8, 9],它是严格递增的。
从下标 5 开始的子数组是 [2, 3, 4],它也是严格递增的。
这两个子数组是相邻的,因此 3 是满足题目条件的最大 k 值。
示例 2:
输入:nums = [1,2,3,4,4,4,4,5,6,7]
输出:2
解释:
从下标 0 开始的子数组是 [1, 2],它是严格递增的。
从下标 2 开始的子数组是 [3, 4],它也是严格递增的。
这两个子数组是相邻的,因此 2 是满足题目条件的最大 k 值。
提示
2 <= nums.length <= 2 * 10^5
-10^9 <= nums[i] <= 10^9
解题思路
要找到满足条件的最大 k
,即存在两个相邻且长度为 k
的严格递增子数组,我们需要有效地遍历数组,并跟踪每个严格递增子数组的长度。
关键点在于:
- 识别严格递增的子数组:我们需要遍历数组,识别出所有严格递增的子数组,并记录它们的长度。
- 检查相邻性:确保找到的两个子数组是相邻的,即第二个子数组紧跟在第一个子数组的后面。
- 寻找最大
k
:在所有可能的相邻子数组对中,找到最大的k
值。
为了实现上述目标,我们可以采用以下策略:
- 遍历数组:逐个元素检查当前元素是否比前一个元素大,以确定是否延续了当前的递增子数组。
- 记录递增子数组的长度:当遇到不再递增的元素时,记录当前递增子数组的长度,并重置计数器以开始新的子数组。
- 比较相邻子数组的长度 :每次记录一个递增子数组的长度时,与之前一个子数组的长度进行比较,更新
k
的值。
代码解析
以下是解决该问题的 Python 代码实现:
python
class Solution:
def maxIncreasingSubarrays(self, nums: List[int]) -> int:
n = len(nums)
ans = pre_cnt = cnt = 0
for i, x in enumerate(nums):
cnt += 1
# 如果当前元素是最后一个,或者下一个元素不再递增
if i == n - 1 or x >= nums[i + 1]:
# 计算可能的 k 值
# cnt // 2 是因为需要两个子数组,每个至少长度 k
# min(pre_cnt, cnt) 确保两个子数组长度一致
ans = max(ans, cnt // 2, min(pre_cnt, cnt))
pre_cnt = cnt
cnt = 0
return ans
代码详解
-
初始化变量:
n
:数组的长度。ans
:存储当前找到的最大k
值。pre_cnt
:记录上一个严格递增子数组的长度。cnt
:当前正在计数的严格递增子数组的长度。
-
遍历数组:
- 使用
enumerate
函数遍历数组的每个元素及其索引。 - 对于每个元素
x
,将cnt
增加 1,表示当前递增子数组长度增加。
- 使用
-
检测递增子数组的结束:
- 如果当前元素是最后一个元素 (
i == n - 1
),或者当前元素不小于下一个元素 (x >= nums[i + 1]
),则说明当前递增子数组结束。
- 如果当前元素是最后一个元素 (
-
更新最大
k
值:- 计算
cnt // 2
,因为需要两个子数组,每个至少长度k
。 - 取
pre_cnt
和cnt
的最小值,确保两个子数组的长度一致。 - 更新
ans
为当前找到的最大值。
- 计算
-
重置计数器:
- 将
pre_cnt
更新为当前的cnt
,为下一个递增子数组做准备。 - 将
cnt
重置为 0,开始新的计数。
- 将
-
返回结果:
- 最终返回
ans
,即满足条件的最大k
值。
- 最终返回
示例解析
示例 1:
输入:nums = [2,5,7,8,9,2,3,4,3,1]
-
递增子数组识别:
[2,5,7,8,9]
长度为 5[2,3,4]
长度为 3[3]
长度为 1[1]
长度为 1
-
相邻子数组对:
[2,5,7,8,9]
和[2,3,4]
:k = min(5,3) = 3
-
最大
k
为 3。
示例 2:
输入:nums = [1,2,3,4,4,4,4,5,6,7]
-
递增子数组识别:
[1,2,3,4]
长度为 4[4]
长度为 1[4]
长度为 1[4,5,6,7]
长度为 4
-
相邻子数组对:
[1,2,3,4]
和[4]
:k = min(4,1) = 1[4]
和[4]
:k = min(1,1) = 1[4]
和[4,5,6,7]
:k = min(1,4) = 1
-
最大
k
为 1。
注意 :在第二个示例中,虽然 [1,2,3,4]
和 [4,5,6,7]
都是严格递增的,但它们不是直接相邻的,因为中间有一个单独的 [4]
。
复杂度分析
- 时间复杂度 :
O(n)
,其中n
是数组的长度。我们只需要遍历数组一次。 - 空间复杂度 :
O(1)
,只使用了常数级别的额外空间。