3254. 长度为 K 的子数组的能量值 I
题目描述
给你一个长度为 n 的整数数组 nums 和一个正整数 k 。
一个数组的 能量值 定义为:
- 如果 所有 元素都是依次 连续 且 上升 的,那么能量值为 最大 的元素。
- 否则为 -1 。
你需要求出 nums 中所有长度为 k 的 子数组 的能量值。
请你返回一个长度为 n - k + 1 的整数数组 results ,其中 results[i] 是子数组 nums[i..(i + k - 1)] 的能量值。
示例 1:
输入:nums = [1,2,3,4,3,2,5], k = 3
输出:[3,4,-1,-1,-1]
解释:
nums 中总共有 5 个长度为 3 的子数组:
[1, 2, 3]中最大元素为 3 。[2, 3, 4]中最大元素为 4 。[3, 4, 3]中元素 不是 连续的。[4, 3, 2]中元素 不是 上升的。[3, 2, 5]中元素 不是 连续的。
示例 2:
输入:nums = [2,2,2,2,2], k = 4
输出:[-1,-1]
示例 3:
输入:nums = [3,2,3,2,3,2], k = 2
输出:[-1,3,-1,3,-1]
提示:
1 <= n == nums.length <= 5001 <= nums[i] <= 1051 <= k <= n
解法
方法一:递推
思考
窗口能量在「元素恰为连续递增」时等于窗口最大,否则为 \(-1\)。\(n\le 500\),每个窗口重扫 \(k\) 格可以过,但相邻窗口的连续性高度重叠。
令 \(f[i]\) 为以 \(i\) 结尾的连续递增长度,则 \(f[i]\ge k\) 当且仅当 \([i-k+1,i]\) 合法,能量为 \(\textit{nums}[i]\)。一遍递推后按右端点输出。
我们定义一个数组 \(f\),其中 \(f[i]\) 表示以第 \(i\) 个元素结尾的连续上升子序列的长度。初始时 \(f[i] = 1\)。
接下来,我们遍历数组 \(\textit{nums}\),计算数组 \(f\) 的值。如果 \(nums[i] = nums[i - 1] + 1\),则 \(f[i] = f[i - 1] + 1\);否则 \(f[i] = 1\)。
然后,我们在 \([k - 1, n)\) 的范围内遍历数组 \(f\),如果 \(f[i] \ge k\),那么答案数组添加 \(\textit{nums}\),否则添加 \(-1\)。
遍历结束后,返回答案数组。
时间复杂度 \(O(n)\),空间复杂度 \(O(n)\)。其中 \(n\) 表示数组 \(\textit{nums}\) 的长度。
1 2 3 4 5 6 7 8 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
方法二:双指针
思考
方法一额外用了 \(O(n)\) 的 \(f\) 数组。连续性只需记住当前递增段的左端 \(j\):一旦相邻差不是 \(1\) 就把 \(j\) 收成 \(i\)。窗口左端若仍不小于 \(j\) 则合法。滚动指针后额外空间 \(O(1)\)。
我们用指针 \(j\) 记录当前「相邻差均为 \(1\)」这一段的起点。从左到右遍历数组:若 \(i > 0\) 且 \(\textit{nums}[i] \neq \textit{nums}[i - 1] + 1\),则将 \(j\) 更新为 \(i\)。
当 \(i \ge k - 1\) 时,当前窗口为 \([i - k + 1,\ i]\)。若 \(i - k + 1 < j\),说明窗口内某对相邻元素之差不是 \(1\),能量值为 \(-1\);否则窗口内元素依次为连续整数,能量值就是窗口最大值 \(\textit{nums}[i]\)。
时间复杂度 \(O(n)\),空间复杂度 \(O(1)\)。其中 \(n\) 表示数组 \(\textit{nums}\) 的长度。
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 | |