leetcode
leetcode 2351 ~ 2400
不间断子数组

不间断子数组

难度:

标签:

题目描述

You are given a 0-indexed integer array nums. A subarray of nums is called continuous if:

  • Let i, i + 1, ..., j be the indices in the subarray. Then, for each pair of indices i <= i1, i2 <= j, 0 <= |nums[i1] - nums[i2]| <= 2.

Return the total number of continuous subarrays.

A subarray is a contiguous non-empty sequence of elements within an array.

 

Example 1:

Input: nums = [5,4,2,4]
Output: 8
Explanation: 
Continuous subarray of size 1: [5], [4], [2], [4].
Continuous subarray of size 2: [5,4], [4,2], [2,4].
Continuous subarray of size 3: [4,2,4].
Thereare no subarrys of size 4.
Total continuous subarrays = 4 + 3 + 1 = 8.
It can be shown that there are no more continuous subarrays.

 

Example 2:

Input: nums = [1,2,3]
Output: 6
Explanation: 
Continuous subarray of size 1: [1], [2], [3].
Continuous subarray of size 2: [1,2], [2,3].
Continuous subarray of size 3: [1,2,3].
Total continuous subarrays = 3 + 2 + 1 = 6.

 

Constraints:

  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 109

代码结果

运行时间: 133 ms, 内存: 24.5 MB


/*
 * 思路:
 * 使用Java Stream API实现相同的逻辑
 */

import java.util.stream.IntStream;

public class ContinuousSubarraysStream {
    public static int countContinuousSubarrays(int[] nums) {
        return IntStream.range(0, nums.length)
                .mapToObj(i -> new int[]{i, i})
                .mapToInt(p -> {
                    int start = p[0];
                    int end = p[1];
                    while (end < nums.length && (end == start || Math.abs(nums[end] - nums[end - 1]) <= 2)) {
                        end++;
                    }
                    return end - start;
                })
                .sum();
    }
}

解释

方法:

该题解采用了一个双指针技术来确定符合条件的不间断子数组。指针i作为子数组的起始点,而指针j从i开始向后遍历,检查每个新元素是否能扩展当前的不间断子数组。为了判断是否满足不间断条件,算法维护了当前子数组中的最大值maxV和最小值minV,并更新这两个值随着j的增加。如果这两个值的差大于2,表明当前子数组已不再满足条件,因此计算到目前为止的所有可能子数组数目,并调整i的位置来尝试新的子数组。如果j到达数组末尾而没有超过范围,那么将当前子数组的计数加入最终结果中。此外,对于单个元素的子数组,最后结果需再加上n。

时间复杂度:

O(n^2)

空间复杂度:

O(1)

代码细节讲解

🦆
在算法中,如何精确地维护并更新maxV和minV的值?是否在每次循环中都重新计算,还是有其他优化方法?
在算法中,maxV和minV的值通过迭代更新,而不是在每次循环中重新计算。每当新的元素被考虑加入到子数组中时,算法检查这个元素是否大于当前的maxV或小于当前的minV,并相应地更新这两个值。这种方法有效利用了前一步的结果,避免了重复的计算,提高了效率。
🦆
为什么在maxV和minV的差大于2时,内部while循环要检查`abs(nums[j] - nums[j - k]) <= 2`?这个条件是如何与题目要求关联的?
当maxV和minV的差大于2时,说明当前子数组已经不满足问题中的条件,即子数组中的任意两个数的差不得超过2。这时内部while循环检查`abs(nums[j] - nums[j - k]) <= 2`是为了回溯并找到最大的符合条件的子数组。这个条件确保即使当前元素导致子数组整体不满足条件,子数组的前一部分仍可能有效。
🦆
题解中提到,当maxV和minV的差大于2时会重新调整i的位置。具体是如何决定新的i的位置?这种调整是否可能导致遗漏某些有效的子数组?
新的i的位置是根据内部while循环的结果确定的,即从当前不满足条件的位置回溯到最后一个可能的有效子数组的起始位置。这种调整是为了尽可能包含更多的元素,同时保证算法效率。理论上,这种方法不会遗漏有效的子数组,因为它是基于当前元素导致的不满足条件来回溯并调整的。
🦆
算法在最后使用了复杂的数学公式来计算子数组的数量,这个计算过程是否正确?具体的公式逻辑是什么?
算法使用的数学公式基于组合数学原理来计算子数组数量。公式`(j - i + 2) * (j - i + 1) / 2 - (j - i + 1)`计算的是从i到j的所有可能的子数组数目,减去单独包含j的情况,以避免重复计数。这个计算是正确的,并能有效地计算出所有可能的子数组数量。

相关问题