基础算法 --- 线性DP

本文详细介绍了线性动态规划(DP)在解决序列问题中的应用,包括最长上升子序列和最短编辑距离。讨论了如何优化最长上升子序列的解法,通过二分查找和TreeSet实现。同时阐述了最长公共子序列的朴素写法。编辑距离部分解释了如何通过状态转移方程找到从一个字符串转换到另一个的最小操作次数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


前言

线性DP同样作为DP领域中非常重要的一部分,其指的是状态之间含有某种线性关系,大多求最大/最小值。最典型的题目为子序列编辑距离股票问题


一、序列问题

1. 最长上升子序列

Acwing 897
给定一个长度为 N 的数列,求数值严格单调递增的子序列的长度最长是多少。
当N的数据量并不大时 (10^4) ,可以直接使用朴素解法,即 O(n^2) 的时间复杂度,否则需要优化解法,即 O(nlogn) 的时间复杂度。

1.1 朴素写法

  1. 设置状态数组f[i],表示以 nums[i] 结尾的数可以构成的最长上升子序列长度。
  2. 状态转移方程: f [ i ] = M a x ( f [ 0 ] , f [ 1 ] , . . . , f [ i − 1 ] ) + 1 f[i] = Max(f[0], f[1], ..., f[i-1]) + 1 f[i]=Max(f[0],f[1],...,f[i1])+1当然括号内的 f[j] 应该满足 n u m s [ i ] > n u m s [ j ] nums[i] > nums[j] nums[i]>nums[j]
import java.util.*;

public class Main {
   
   
    public static void main(String[] args) {
   
   
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int[] nums = new int[n];
        for (int i = 0; i < n; i ++) {
   
   
            nums[i] = in.nextInt();
        }
        int[] f = new int[n];
        
        Arrays.fill(f, 1);
        
        for (int i = 1; i < n; i ++) {
   
   
            for (int j = 0; j < i; j ++) {
   
   
                if (nums[i] > nums[j]) {
   
   
                    f[i] = Math.max(f[i], f[j] + 1);
                }
            }
        }
        
        System.out.println(Arrays.stream(f).max().getAsInt());
    }
}

1.2 优化写法

时间复杂度 O(nlogn),可以理解为以 O(n) 的时间复杂度来遍历整个数组,再用 O(logn) 的时间复杂度来确定每一个数所能构成的最优最长上升子序列。

  1. 构造遍历到当前数的最长上升子序列数组 ans
  2. 通过二分查找确定当前数t的最优插入位置,即插入到大于等于t的第一个数的下标位置,如果插入位置的数等于 t 则覆盖。
  3. 第二步保证的是以 t 结尾且长度为 x 的最长上升子序列的各部分最大值最小。
1.2.1 二分写法
import java.util.*;

public class Main {
   
   
<think>好的,我现在需要帮助用户了解Smith-Waterman算法与非线性的关系以及其实现和优化。首先,我需要回忆一下Smith-Waterman算法的基本知识。这个算法是用于局部序列比对的动态规划算法,通常用于生物信息学中比较DNA、RNA或蛋白质序列。 用户提到“非线性”,我需要确定这里指的是什么。可能是指算法的时间或空间复杂度不是线性的,或者算法在实现过程中涉及非线性结构或处理方式。另外,用户可能想知道如何优化该算法,尤其是在处理大规模数据时的效率问题。 首先,回顾动态规划的基本原理。Smith-Waterman使用动态规划表格,每个单元格(i,j)表示两个序列中前i和j个元素的最佳比对得分。计算每个单元格需要考虑三个方向:上方、左侧和左上角,分别对应插入、删除和匹配/不匹配的操作。这通常导致时间和空间复杂度都是O(nm),其中n和m是两个序列的长度。对于长序列来说,这会导致较高的计算成本,因此需要优化。 接下来,关于非线性方面。标准的动态规划算法的时间复杂度是二次的,即O(nm),属于非线性复杂度。当处理非常大的序列时,这可能导致计算时间过长。因此,优化方法可能涉及降低时间复杂度或空间复杂度,例如使用启发式方法减少计算量,或者采用并行计算等技术。 然后,实现优化方面,常见的优化方法包括使用滚动数组来减少空间复杂度,从O(nm)降到O(min(n,m))。另外,考虑分治策略,如Hirschberg算法,可以在线性空间内计算最优比对。还有并行化处理,利用GPU或多核CPU加速计算。此外,近似算法或启发式方法(如BLAST中的策略)可以快速找到近似最优解,牺牲一定的精度以换取效率。 需要确认用户提到的“非线性”是否涉及其他方面,例如算法中的非线性决策过程或复杂的数据结构。但根据常见问题,可能还是指复杂度方面的非线性,即二次复杂度。此外,可能需要引用站内资料,比如引用[1]提到的局部比对矩阵和动态规划的实现,以及引用[4]中提到的近似算法思想。 在回答结构上,需要先介绍算法,再分析其非线性特性,然后讨论实现优化方法。最后生成相关问题,帮助用户进一步学习。 需要注意使用正确的中文表达,数学公式用$$...$$,行内公式用$...$。例如,动态规划的递推公式需要用行内格式,而得分矩阵的表示可能需要独立公式。 最后,检查引用是否正确,引用[1]提到了Smith-Waterman和序列比对,引用[4]讨论了近似算法,可能相关。需要确保引用的自然插入,例如在讨论优化方法时提到近似算法可以引用[4]。</think>### Smith-Waterman算法的非线性特性与优化 #### 1. **算法基础** Smith-Waterman算法是一种基于动态规划的局部序列比对算法,用于生物序列(如DNA、蛋白质)的相似性分析。其核心是构建得分矩阵$H$,并通过递推公式计算每个单元$(i,j)$的最优比对得分: $$ H(i,j) = \max \begin{cases} 0 \\ H(i-1,j-1) + s(a_i,b_j) \\ H(i-1,j) - d \\ H(i,j-1) - d \end{cases} $$ 其中$s(a_i,b_j)$为匹配得分,$d$为插入/删除的罚分[^1]。 #### 2. **非线性特性分析** - **时间复杂度**:算法需要遍历二维矩阵的所有单元,时间复杂度为$O(nm)$($n,m$为序列长度),属于**二次复杂度**,即非线性增长。 - **空间复杂度**:存储完整得分矩阵需$O(nm)$空间,同样非线性- **计算依赖**:每个单元$(i,j)$的计算依赖于左、上、左上三个相邻单元,形成**非线性数据依赖关系**,限制了并行化潜力。 #### 3. **实现优化方法** ##### (1) **空间优化** 使用**滚动数组**将空间复杂度降至$O(\min(n,m))$,仅保留当前行和上一行的数据[^1]。 ```python def smith_waterman(a, b, match=2, mismatch=-1, gap_penalty=1): dp = [[0]*(len(b)+1) for _ in range(2)] # 仅两行 max_score = 0 for i in range(1, len(a)+1): for j in range(1, len(b)+1): match_score = dp[(i-1)%2][j-1] + (match if a[i-1]==b[j-1] else mismatch) delete = dp[(i-1)%2][j] - gap_penalty insert = dp[i%2][j-1] - gap_penalty dp[i%2][j] = max(0, match_score, delete, insert) max_score = max(max_score, dp[i%2][j]) return max_score ``` ##### (2) **启发式剪枝** - **Band-limited DP**:假设最优比对在主干对角线附近,仅计算带状区域的单元,将时间降至$O(kn)$($k$为带宽)[^4]。 - **阈值过滤**:忽略得分低于阈值的路径,减少无效计算。 ##### (3) **并行化加速** - **GPU加速**:利用CUDA等框架将矩阵计算分配到GPU线程块,适合大规模序列比对。 - **SIMD指令**:通过单指令多数据技术优化CPU端的向量化计算。 ##### (4) **近似算法** 如BLAST工具通过**种子扩展策略**快速定位高相似区域,再局部精细化比对,牺牲精度以换取效率。 ####
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值