📜  门| GATE CS Mock 2018 |设置 2 |第 50 题(1)

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

GATE CS Mock 2018 | 设置 2 | 第 50 题

这道题目要求我们找到一个长度为n的01序列的最长子序列,其满足相邻的两个1的距离至少为k。

算法思路

我们考虑动态规划的方式求解。定义f[i]表示以第i位为结尾的最长子序列长度,那么状态转移方程为:

$$ f[i] = \begin{cases} 0, & \text{if $s[i] = 0$} \ 1, & \text{if $i=1$} \ max{f[j]} + 1, & \text{if $i-j \ge k+1$ and $s[j] = 1$} \ \end{cases} $$

其中,$s[i]$表示第i位的值,即0或1。

代码实现
def longest_subsequence(s, k):
    n = len(s)
    f = [0] * n
    ans = 0
    for i in range(n):
        if s[i] == 1:
            f[i] = 1
            for j in range(i-1, -1, -1):
                if i-j >= k+1 and s[j] == 1:
                    f[i] = max(f[i], f[j]+1)
            ans = max(ans, f[i])
    return ans

其中,s为给定的01序列,k为相邻两个1的最小距离。返回值为最长子序列的长度。

时间复杂度

时间复杂度为$O(n^2)$,其中n为序列的长度。一般而言,这样的时间复杂度在n稍微大一点的时候就会超时。但是我们可以对算法进行优化,使得时间复杂度降为$O(n)$。具体优化思路如下:

  • 对原始序列进行预处理,找到其中所有满足相邻两个1距离不小于k的位置,形成新的序列。
  • 对新的序列进行动态规划求解,时间复杂度降为$O(m)$,其中m为新序列的长度。

代码如下:

def longest_subsequence(s, k):
    n = len(s)
    pos = [-1]
    for i in range(n):
        if s[i] == 1 and i-pos[-1] > k:
            pos.append(i)
    pos.append(n)
    ans = 0
    m = len(pos)
    f = [0] * m
    for i in range(m):
        if i == 0:
            f[i] = 0
        elif pos[i] - pos[i-1] == 1:
            f[i] = f[i-1]
        else:
            f[i] = max(f[i-1], f[i-2]+pos[i]-pos[i-2]-1)
        ans = max(ans, f[i])
    return ans

其中,pos为新序列中1的位置。