📜  包含卢卡斯数的数组的最长子序列(1)

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

包含卢卡斯数的数组的最长子序列

在计算机科学中,有一个经典问题是要找出一个数组的最长不递减子序列(Longest Increasing Subsequence,LIS)。现在有一个要求更高的问题:找出一个数组的最长不递减子序列,并且该子序列中必须包含卢卡斯数。

什么是卢卡斯数?

卢卡斯数列是一个类似于斐波那契数列的数列,对于第 $n$ 个数 $L_n$,其定义为:

$$ L_n=\begin{cases} 2, & n=0 \ 1, & n=1 \ L_{n-1}+L_{n-2}, & n \geq 2 \end{cases} $$

卢卡斯数列的前几个数是:2, 1, 3, 4, 7, 11, 18, 29, ...

思路

与 LIS 问题类似,我们可以使用动态规划来解决该问题。

我们可以定义一个状态数组 $dp$,其中 $dp[i]$ 表示以输入数组的第 $i$ 个元素结尾的最长不递减子序列并且该子序列中必须包含卢卡斯数的长度。

假设输入数组为 $a$,卢卡斯数列为 $l$,则状态转移方程为:

$$ dp[i]=\begin{cases} 1, & a[i]=l_0 \ \max\limits_{j=0}^{i-1}{dp[j]+1}, & a[i]>a[j] \land a[j] \in {l_0, l_1, ..., l_{i-1}} \ \max\limits_{j=0}^{i-1}{dp[j]}, & a[i] \leq a[j] \land a[j] \in {l_0, l_1, ..., l_{i-1}} \end{cases} $$

其中 $a[i]$ 表示输入数组的第 $i$ 个元素,$l_0, l_1, ..., l_{i-1}$ 表示卢卡斯数列中第 $0$ 到第 $i-1$ 个元素。

最终的答案就是 $dp$ 数组中的最大值。

代码实现

下面是该问题的代码实现(Python):

def lis_with_lucas(nums):
    l = [2, 1]
    n = 2
    while l[-1] < nums[-1]:
        l.append(l[-1] + l[-2])
        n += 1
    dp = [1] * len(nums)
    for i in range(len(nums)):
        for j in range(i):
            if nums[i] > nums[j] and nums[j] in l[:i]:
                dp[i] = max(dp[i], dp[j] + 1)
            elif nums[i] <= nums[j] and nums[j] in l[:i]:
                dp[i] = max(dp[i], dp[j])
    return max(dp)

其中变量命名与状态转移方程一致,较容易理解。