牛客题解 | 最长公共子序列(一)

题目## 题目

题目链接

解题思路

  1. 定义 d p [ i ] [ j ] dp[i][j] dp[i][j] 表示 s 1 s1 s1 的前 i i i 个字符和 s 2 s2 s2 的前 j j j 个字符的最长公共子序列长度
  2. 如果 s 1 [ i − 1 ] = = s 2 [ j − 1 ] s1[i-1] == s2[j-1] s1[i1]==s2[j1],则 d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] + 1 dp[i][j] = dp[i-1][j-1] + 1 dp[i][j]=dp[i1][j1]+1
  3. 如果 s 1 [ i − 1 ] ! = s 2 [ j − 1 ] s1[i-1] != s2[j-1] s1[i1]!=s2[j1],则 d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] , d p [ i ] [ j − 1 ] ) dp[i][j] = max(dp[i-1][j], dp[i][j-1]) dp[i][j]=max(dp[i1][j],dp[i][j1])
  4. 最终答案为 d p [ n ] [ m ] dp[n][m] dp[n][m]

代码

#include <iostream>
#include <vector>
#include <string>
using namespace std;

int main() {
    int n, m;
    cin >> n >> m;
    string s1, s2;
    cin >> s1 >> s2;
    
    vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0));
    
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            if(s1[i-1] == s2[j-1]) {
                dp[i][j] = dp[i-1][j-1] + 1;
            } else {
                dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
            }
        }
    }
    
    cout << dp[n][m] << endl;
    return 0;
}
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        String s1 = sc.next();
        String s2 = sc.next();
        
        int[][] dp = new int[n + 1][m + 1];
        
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= m; j++) {
                if(s1.charAt(i-1) == s2.charAt(j-1)) {
                    dp[i][j] = dp[i-1][j-1] + 1;
                } else {
                    dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
                }
            }
        }
        
        System.out.println(dp[n][m]);
    }
}
n, m = map(int, input().split())
s1 = input()
s2 = input()

dp = [[0] * (m + 1) for _ in range(n + 1)]

for i in range(1, n + 1):
    for j in range(1, m + 1):
        if s1[i-1] == s2[j-1]:
            dp[i][j] = dp[i-1][j-1] + 1
        else:
            dp[i][j] = max(dp[i-1][j], dp[i][j-1])

print(dp[n][m])

算法及复杂度

  • 算法:动态规划
  • 时间复杂度: O ( m n ) \mathcal{O}(mn) O(mn) - 两层嵌套循环遍历
  • 空间复杂度: O ( m n ) \mathcal{O}(mn) O(mn) - 需要一个 m × n m×n m×n d p dp dp 数组


[题目链接](https://www.nowcoder.com/practice/5f65ccbb025240bd8458eb6479c2612e?tpId=308&tqId=2357994&sourceUrl=/exam/oj&channelPut=wcsdn&fromPut=wcsdn)

## 解题思路

这是一个经典的动态规划问题。我们可以用以下思路解决:

1. 定义 $dp[i]$ 表示以第i个数字结尾的最长上升子序列的长度
2. 对于每个位置 $i$,遍历它前面的所有位置 $j$
3. 如果 $arr[i] > arr[j]$,说明可以将 $arr[i]$ 接在以 $arr[j]$ 结尾的上升子序列后面
4. 状态转移方程:$dp[i] = max(dp[j] + 1)$ 其中 $j < i$ 且 $arr[j] < arr[i]$
5. 最终答案为 $dp$ 数组中的最大值

---

## 代码

```c++ []
#include <iostream>
#include <vector>
using namespace std;

int main() {
    int n;
    cin >> n;
    vector<int> arr(n);
    for(int i = 0; i < n; i++) {
        cin >> arr[i];
    }
    
    vector<int> dp(n, 1);  // 初始化dp数组,每个元素至少是长度为1的子序列
    int maxLen = 1;
    
    for(int i = 1; i < n; i++) {
        for(int j = 0; j < i; j++) {
            if(arr[i] > arr[j]) {
                dp[i] = max(dp[i], dp[j] + 1);
            }
        }
        maxLen = max(maxLen, dp[i]);
    }
    
    cout << maxLen << endl;
    return 0;
}
```
```java []
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] arr = new int[n];
        for(int i = 0; i < n; i++) {
            arr[i] = sc.nextInt();
        }
        
        int[] dp = new int[n];
        Arrays.fill(dp, 1);  // 初始化dp数组
        int maxLen = 1;
        
        for(int i = 1; i < n; i++) {
            for(int j = 0; j < i; j++) {
                if(arr[i] > arr[j]) {
                    dp[i] = Math.max(dp[i], dp[j] + 1);
                }
            }
            maxLen = Math.max(maxLen, dp[i]);
        }
        
        System.out.println(maxLen);
    }
}
```
```python []
n = int(input())
arr = list(map(int, input().split()))

dp = [1] * n  # 初始化dp数组

for i in range(1, n):
    for j in range(i):
        if arr[i] > arr[j]:
            dp[i] = max(dp[i], dp[j] + 1)

print(max(dp))
```

---

## 算法及复杂度
- 算法:动态规划
- 时间复杂度:$\mathcal{O}(n^2)$ - 两层嵌套循环
- 空间复杂度:$\mathcal{O}(n)$ - 需要一个长度为 $n$ 的 $dp$ 数组
````


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值