牛客题解 | 最长上升子序列(一)

题目

题目链接

解题思路

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

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

代码

#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;
}
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);
    }
}
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))

算法及复杂度

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值