📜  门| GATE CS 2019 |第 30 题(1)

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

题目描述

给定一个大小为$n$的正整数数组$A$。定义一个非空子数组$B$为锯齿数组当且仅当以下条件都满足:

  • $B$ 中的所有元素是正整数。
  • $如果B$ 的长度为$1$,则B是锯齿数组。
  • 如果$B$ 的长度大于$1$,则$需要B$ 中的相邻元素交替极大值和极小值:$B_{1}>B_{2}<B_{3}>B_{4}<B_{5} \cdots$。

例如,$[3,1,4]$、$[1,3,2,4]$、$[1,2,1,2,1,2]$、$[4,2,3,1,5]$ 是锯齿数组,但是 $[1,1,1,1]$、$[4,5,6,3]$、$[3,3,3,2,5]$ 不是。

你的任务是找到数组$A$ 的所有可能的锯齿子数组并且返回这些子数组的数量。数组$A$ 可以按任意顺序排序。

输入格式

第一行是一个正整数 $T$,表示测试用例的数量。对于每个测试用例,第一行是一个整数$n$,表示数组$A$ 的长度。接下来一行有$n$个以空格分隔的整数 $A_0 A_1 \cdots A_{n-1}$

输出格式

对于每个测试用例,输出一个整数,表示由数组$A$ 构成的所有可能的锯齿子数组的数量。

样例

输入样例
2
4
4 2 3 1 
6
1 2 3 4 5 6
输出样例
4
21

题解

这道题可以使用动态规划来求得,具体实现如下:

  • 让 $up[i]$ 表示以 $i$ 结尾的最后一个元素是极大值的锯齿子数组的数量,初始化 $up[i] = 1$。
  • 让 $down[i]$ 表示以 $i$ 结尾的最后一个元素是极小值的锯齿子数组的数量,初始化 $down[i] = 1$。
  • 当 $A[i] > A[i - 1]$ 时分两种情况:
    • 如果前一个是极小值,以当前元素结尾的极大值锯齿子数组的数量是 $up[i - 1] + 1$,以当前元素结尾的极小值锯齿子数组的数量不变,即 $down[i] = down[i - 1]$。
    • 如果前一个是极大值,以当前元素结尾的极小值锯齿子数组的数量是 $up[i - 1] + 1$,以当前元素结尾的极大值锯齿子数组的数量不变,即 $up[i] = up[i - 1]$。
  • 当 $A[i] < A[i - 1]$ 时同样分两种情况:
    • 如果前一个是极大值,以当前元素结尾的极小值锯齿子数组的数量是 $down[i - 1] + 1$,以当前元素结尾的极大值锯齿子数组的数量不变,即 $up[i] = up[i - 1]$。
    • 如果前一个是极小值,以当前元素结尾的极大值锯齿子数组的数量是 $down[i - 1] + 1$,以当前元素结尾的极小值锯齿子数组的数量不变,即 $down[i] = down[i - 1]$。

最后把所有的 $up[i]$ 和 $down[i]$ 相加即可得到所有可能的锯齿子数组的数量。

时间复杂度为$O(n)$。

代码片段
def find_zigzag_subsequences(n, array):
    up = [1] * n
    down = [1] * n
    
    for i in range(1, n):
        if array[i] > array[i-1]:
            up[i] = down[i-1] + 1
            down[i] = down[i-1]
        elif array[i] < array[i-1]:
            down[i] = up[i-1] + 1
            up[i] = up[i-1]
        else:
            up[i] = up[i-1]
            down[i] = down[i-1]
    return up[-1] + down[-1] - 1

t = int(input())
for _ in range(t):
    n = int(input())
    array = list(map(int, input().split()))
    ans = find_zigzag_subsequences(n, array)
    print(ans)