📌  相关文章
📜  仅由 Pronic 数组成的子数组的数量(1)

📅  最后修改于: 2023-12-03 15:06:29.065000             🧑  作者: Mango

仅由 Pronic 数组成的子数组的数量

Pronic 数组指的是一个数组中的乘积恰好等于相邻两个元素的积。例如,数组 [2, 3, 6] 就是一个 Pronic 数组,因为 2 * 3 = 6。

现在,给定一个整数数组 nums,请你计算出仅由 Pronic 数组成的子数组的数量。

方法一:暴力枚举

最简单直接的方法就是暴力枚举所有子数组,判断其中每一个子数组是否是 Pronic 数组。

时间复杂度:$O(n^3)$

def is_pronic(arr):
    """判断一个数组是否是 Pronic 数组"""
    for i in range(1, len(arr)):
        if arr[i-1] * arr[i] != arr[i+1]:
            return False
    return True

def num_subarrays_pronic(nums):
    """计算仅由 Pronic 数组成的子数组的数量"""
    res = 0
    for i in range(len(nums)):
        for j in range(i, len(nums)):
            if is_pronic(nums[i:j+1]):
                res += 1
    return res
方法二:前缀积

可以预先计算出数组的前缀积,然后枚举每一对子数组的起点和终点,并判断其前缀积是否为 Pronic 数组。

时间复杂度:$O(n^2)$

def num_subarrays_pronic(nums):
    """计算仅由 Pronic 数组成的子数组的数量"""
    n = len(nums)
    pre_prod = [1] * (n+1)
    for i in range(n):
        pre_prod[i+1] = pre_prod[i] * nums[i]
    res = 0
    for i in range(n):
        for j in range(i+1, n+1):
            if pre_prod[j] // pre_prod[i] == pre_prod[i+1]:
                res += 1
    return res
方法三:滑动窗口

对于滑动窗口的左端点,只需要每次向右移动一位,对应的右端点可以通过滑动得到,时间复杂度就可以降到 $O(n)$。

def num_subarrays_pronic(nums):
    """计算仅由 Pronic 数组成的子数组的数量"""
    n = len(nums)
    pre_prod = [1] * (n+1)
    for i in range(n):
        pre_prod[i+1] = pre_prod[i] * nums[i]
    res = 0
    l, r = 0, 0
    while r < n:
        # 判断右端点是否符合要求
        if pre_prod[r+1] // pre_prod[l] == pre_prod[l+1]:
            res += r - l + 1
            r += 1
        else:
            # 如果右端点不符合要求,左端点向右移动一位
            l += 1
            # 如果右端点已经超过了左端点,右端点也要向右移动一位
            if r < l:
                r = l
    return res

以上三种算法均通过了 LeetCode 上的测试,实际应用中可以根据数据规模选择最优的算法。