派派的刷题之旅(二) | 豆包MarsCode AI 刷题

23 阅读4分钟

最小替换子串长度

问题描述

给定一个包含 N 个整数的数组 A,其中每个元素编号从 0 到 N-1,并且一个整数 K。数组 A 的每个元素都在 1 到 K 的范围内。

定义一个长度为 N 的数组 B 为好数组,如果它满足以下条件:

  1. 每个元素 B[i] 都在 1 到 K 的范围内。
  2. 对于所有从 0 到 N-2 的索引 i,满足 B[i] + B[i+1] = A[i] + A[i+1]

你的任务是计算满足上述条件的好数组的总数。

测试样例

样例1:

输入:N = 3, K = 2, A = [1, 2, 1]
输出:2

样例2:

输入:N = 4, K = 3, A = [1, 3, 2, 1]
输出:1

样例3:

输入:N = 2, K = 1, A = [1, 1]
输出:1

思路解析

我们需要找到满足特定条件的数组 B 的数量。具体条件是:

  1. 数组 B 的长度为 N,且每个元素 B[i] 都在 1 到 K 的范围内。
  2. 对于所有从 0 到 N-2 的索引 i,满足 B[i] + B[i+1] = A[i] + A[i+1]

可以使用动态规划(Dynamic Programming)来解决这个问题。定义一个二维数组 dp,其中 dp[i][j] 表示在位置 i 时,B[i] 取值为 j 的情况下,满足条件的数组 B 的数量。

解题代码

def solution(N: int, K: int, A: list[int]) -> int:
    # 初始化 dp 数组
    dp = [[0] * (K + 1) for _ in range(N)]
    
    # 初始化第一个位置
    for j in range(1, K + 1):
        dp[0][j] = 1  # 隐藏关键步骤
    
    # 状态转移
    for i in range(1, N):
        for j in range(1, K + 1):
            for k in range(1, K + 1):
                if j + k == A[i-1] + A[i]:  # 隐藏关键步骤
                    dp[i][j] += dp[i-1][k]  # 隐藏关键步骤
    
    # 计算最终结果
    result = sum(dp[N-1][j] for j in range(1, K + 1))  # 隐藏关键步骤
    
    return result

代码模块详解

  1. 初始化:对于第一个位置 i=0B[0] 可以是 1 到 K 中的任意一个值。因此,dp[0][j] = 1 对于所有 1 <= j <= K
  2. 状态转移:对于每个位置 i 从 1 到 N-1,我们需要计算 dp[i][j]。对于每个可能的 B[i] 值 j,我们需要找到所有可能的 B[i-1] 值 k,使得 B[i-1] + B[i] = A[i-1] + A[i]
  3. 结果:最终结果是所有可能的 B[N-1] 值的和,即 sum(dp[N-1][j]) 对于所有 1 <= j <= K

复杂度分析

时间复杂度分析

当前代码使用了三重循环来实现动态规划的状态转移。具体来看:

  1. 外层循环:遍历数组 A 的每个位置 i,从 1 到 N-1。这个循环的时间复杂度是 O(N)
  2. 中层循环:对于每个位置 i,遍历所有可能的 B[i] 值 j,从 1 到 K。这个循环的时间复杂度是 O(K)
  3. 内层循环:对于每个位置 i 和每个可能的 B[i] 值 j,遍历所有可能的 B[i-1] 值 k,从 1 到 K。这个循环的时间复杂度是 O(K)

因此,总的时间复杂度是 O(N * K * K),即 O(N * K^2)

空间复杂度分析

当前代码使用了一个二维数组 dp 来存储动态规划的状态。具体来看:

  1. 二维数组 dpdp 的大小是 N * (K + 1),因为我们需要存储每个位置 i 的所有可能的 B[i] 值的状态。因此,空间复杂度是 O(N * K)

总结

  • 时间复杂度O(N * K^2)

  • 空间复杂度O(N * K)

总结和思考

  1. 问题分解

    • 将问题分解为更小的子问题,逐步解决。
    • 确定每个子问题的状态和状态转移方程。
  2. 状态转移优化

    • 尝试减少状态转移的复杂度,例如通过预处理或使用更高效的数据结构。
    • 考虑是否可以使用滚动数组或其他技巧来优化空间复杂度。
  3. 边界条件

    • 确保正确处理边界条件,例如数组的第一个和最后一个位置。
    • 初始化状态时要特别注意,确保初始状态正确。