📜  门| GATE CS 2021 |套装2 |问题27(1)

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

门 | GATE CS 2021 |套装2 |问题27

本题考察的是动态规划技巧,需要找到一种有效的方法来解决问题。

题目描述

有一个长度为 $n$ 的字符数组,已经按照字典序排好序了。现在给定一个字符 $x$,请找到插入 $x$ 后得到的新的排好序的字符数组。

输入格式
  • 字符串数组 $a$,长度为 $n$,已经按照字典序排好序。
  • 待插入的字符 $x$。
输出格式
  • 排序后的字符串数组。
思路分析

要求插入 $x$ 后得到新的排序字符数组,首先可以找到一个规律:若将 $x$ 插入到 $a_i$ 和 $a_{i+1}$ 之间,那么得到的新的排序字符数组的前 $i$ 位和原始字符数组的前 $i$ 位是相同的。

假设 $dp_{i,j}$ 表示将 $x$ 插入到 $a_j$ 和 $a_{j+1}$ 之间得到新的排序字符数组的前 $i$ 位,求解 $dp_{n,j}$ 即可得到排序后的字符串数组。

对于 $dp_{i,j}$ 进行动态规划。显然,当 $i=1$ 时,$dp_{1,j}$ 的值即为插入 $x$ 后得到的新的排序字符数组的前一位。

当 $i>1$ 时,可以依据前面提到的规律,得到状态转移方程:

$$dp_{i,j}=dp_{i-1,j},\ \mathrm{if}\ x>a_i$$

$$dp_{i,j}=dp_{i-1,j-1},\ \mathrm{if}\ x<a_{j-1}$$

$$dp_{i,j}=dp_{i-1,j-1}+1,\ \mathrm{if}\ x \in [a_{j-1},a_i]$$

代码实现
def sorted_array(a, x):
    n = len(a)
    dp = [[0] * (n+1) for _ in range(n+1)]
    dp[1][0] = x
    if x > a[0]:
        dp[1][1] = a[0]
    else:
        dp[1][1] = x
        dp[1][0] = a[0]
    for i in range(2, n+2):
        for j in range(1, i+1):
            if j == 1:
                if x >= a[0]:
                    dp[i][j] = dp[i-1][j-1] + 1
                else:
                    dp[i][j] = dp[i-1][j]
            elif j == i:
                if x <= a[i-2]:
                    dp[i][j] = dp[i-1][j-1] + 1
                else:
                    dp[i][j] = dp[i-1][j-2]
            else:
                if x > a[j-2]:
                    dp[i][j] = dp[i-1][j-1]
                elif x < a[j-2]:
                    dp[i][j] = dp[i-1][j]
                else:
                    dp[i][j] = dp[i-1][j-1] + 1
    k = 0
    for i in range(1, n+2):
        if dp[n+1-i][i] != 0:
            k = i
    res = []
    for i in range(1, k):
        res.append(dp[k-i][i])
    res.append(x)
    for i in range(k, n+1):
        res.append(dp[n+1-k][i])
    return res
复杂度分析
  • 时间复杂度:$O(n^2)$(最坏情况下,需要计算 $dp_{i,j}$ 共 $\frac{n(n+1)}{2}$ 个,而每次计算需要常数时间)
  • 空间复杂度:$O(n^2)$(需要开辟一个 $2$ 维数组来存储 $dp_{i,j}$)