leetcode
leetcode 2701 ~ 2750
匹配模式数组的子数组数目 II

匹配模式数组的子数组数目 II

难度:

标签:

题目描述

You are given a 0-indexed integer array nums of size n, and a 0-indexed integer array pattern of size m consisting of integers -1, 0, and 1.

A subarray nums[i..j] of size m + 1 is said to match the pattern if the following conditions hold for each element pattern[k]:

  • nums[i + k + 1] > nums[i + k] if pattern[k] == 1.
  • nums[i + k + 1] == nums[i + k] if pattern[k] == 0.
  • nums[i + k + 1] < nums[i + k] if pattern[k] == -1.

Return the count of subarrays in nums that match the pattern.

 

Example 1:

Input: nums = [1,2,3,4,5,6], pattern = [1,1]
Output: 4
Explanation: The pattern [1,1] indicates that we are looking for strictly increasing subarrays of size 3. In the array nums, the subarrays [1,2,3], [2,3,4], [3,4,5], and [4,5,6] match this pattern.
Hence, there are 4 subarrays in nums that match the pattern.

Example 2:

Input: nums = [1,4,4,1,3,5,5,3], pattern = [1,0,-1]
Output: 2
Explanation: Here, the pattern [1,0,-1] indicates that we are looking for a sequence where the first number is smaller than the second, the second is equal to the third, and the third is greater than the fourth. In the array nums, the subarrays [1,4,4,1], and [3,5,5,3] match this pattern.
Hence, there are 2 subarrays in nums that match the pattern.

 

Constraints:

  • 2 <= n == nums.length <= 106
  • 1 <= nums[i] <= 109
  • 1 <= m == pattern.length < n
  • -1 <= pattern[i] <= 1

代码结果

运行时间: 199 ms, 内存: 57.5 MB


/*
 * 思路:
 * 1. 使用IntStream来遍历nums数组的每个可能起点。
 * 2. 对于每个起点,使用Stream.allMatch来检查子数组中的每个元素是否符合pattern的要求。
 * 3. 统计所有符合要求的子数组数量。
 */

import java.util.stream.IntStream;

public class Solution {
    public int countPatternMatches(int[] nums, int[] pattern) {
        int n = nums.length;
        int m = pattern.length;

        return (int) IntStream.range(0, n - m)
            .filter(i -> IntStream.range(0, m)
                .allMatch(j -> (pattern[j] == 1 && nums[i + j + 1] > nums[i + j]) ||
                               (pattern[j] == 0 && nums[i + j + 1] == nums[i + j]) ||
                               (pattern[j] == -1 && nums[i + j + 1] < nums[i + j])))
            .count();
    }
}

解释

方法:

本题解首先将`nums`数组转换为一个字符序列`s`,其中每个字符代表相邻元素之间的关系:'a' 表示递减,'b' 表示相等,'c' 表示递增。接着,根据`pattern`数组生成一个目标模式字符串`t`,其中每个字符是基于`pattern`元素映射得到(-1映射为'a', 0映射为'b', 1映射为'c')。随后,代码利用字符串匹配的KMP算法中的前缀函数来查找字符串`t`在`s`中的所有出现位置,每个匹配的位置都代表一个符合条件的子数组。最后,返回这些匹配的数量。

时间复杂度:

O(n + m)

空间复杂度:

O(n + m)

代码细节讲解

🦆
在将nums数组转换为表示元素关系的字符串s时,如果nums数组长度小于2,该如何处理?
如果nums数组长度小于2,则无法形成任何相邻元素的比较关系。因此,在这种情况下,字符串s将为空字符串。由于没有可比较的元素关系,直接返回匹配模式的数量为0会是合理的处理方式。
🦆
为什么选择使用KMP算法进行字符串匹配,而不是使用其他字符串匹配算法如Rabin-Karp或Boyer-Moore?
KMP算法被选择用于字符串匹配主要是因为它提供了线性时间复杂度(O(n+m),其中n是文本长度,m是模式长度),且不需要额外的空间复杂度(除了存储前缀函数所需的空间)。这使得KMP算法非常适合在字符串搜索中实现高效和稳定的性能。相比之下,Rabin-Karp算法虽然在平均情况下也有较好的性能,但在最坏情况下会退化到O(n*m);而Boyer-Moore算法虽然在最好情况下非常高效,但其实现较为复杂,且在最坏情况下性能也可能不稳定。
🦆
在构建目标模式字符串t时,假设pattern数组中包含除-1, 0, 1之外的其他整数,该如何处理?
在题目中,pattern数组应只包含-1,0和1这三种值,分别对应于递减、相等和递增的关系。如果pattern数组包含除这三个值之外的其他整数,这将是一个异常情况,因为没有定义如何将这些值转换为'a'、'b'或'c'。在实际实现中,应当对输入进行验证,确保不包含无效的整数。如果遇到无效的整数,可以抛出异常或返回错误信息,提示输入数据不符合预期。

相关问题