力扣HOT100(52)动态规划 - 最长递增子序列

先搞懂:什么是「子序列」?

这是新手最容易搞混的点,一定要和「子串」区分开:

  • 子串 :必须是数组中连续的一段元素
  • 子序列 :可以不连续,但元素的相对顺序不能变

比如数组 [10,9,2,5,3,7,101,18]:

  • 子串:[2,5,3](连续)
  • 子序列:[2,3,18](不连续,但顺序不变)

题目要求

找到数组中最长的严格递增子序列的长度

  • 严格递增:后一个元素必须大于前一个,不能等于
  • 子序列可以不连续,但顺序不能乱

核心思路(一句话讲透)

用 dp[i] 表示:以第 i 个元素结尾的最长递增子序列的长度 。 对于每个元素 nums[i],我们看它前面所有比它小的元素 nums[j](j < i):

  • 如果 nums[j] < nums[i],说明 nums[i] 可以接在 nums[j] 后面,形成一个更长的子序列
  • 这个更长的子序列长度就是 dp[j] + 1
  • 我们在所有可能的 dp[j] + 1 中取最大值,就是 dp[i] 的值

所以状态转移方程:

plaintext

复制代码
dp[i] = max(dp[j] + 1)  (其中 0 ≤ j < i 且 nums[j] < nums[i])

完整解题步骤

  1. 处理边界情况:如果数组为空,直接返回 0
  2. 初始化 dp 数组 :
    • 数组长度为 n(和原数组一样长)
    • 所有元素初始化为1(因为每个元素自己就是一个长度为 1 的子序列)
  3. 遍历计算 dp 数组 :
    • 外层循环:i从0到n-1(当前要计算的元素)
    • 内层循环:j从0到i-1(前面所有的元素)
      • 如果 nums[j] < nums[i](可以接在后面)
      • 更新 dp[i] = max(dp[i], dp[j] + 1)
  4. 返回结果 :dp 数组中的最大值
    • 注意:最长子序列不一定以最后一个元素结尾,所以不能直接返回dp[n-1]
cpp 复制代码
class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        int n = nums.size();
        if(n == 0)
            return 0;


        vector<int> dp(n,1);//初始值设成1 因为序列最短包括自己 长度为1

        for(int i = 0;i<n;i++){
            for(int j = 0;j<i;j++){
                if(nums[j]<nums[i]){
                    dp[i] = max(dp[i],dp[j]+1);
                }
            }
        }  

        return *max_element(dp.begin(),dp.end());
    }
};
相关推荐
一去不复返的通信er5 小时前
力扣-图论-岛屿数量
算法·leetcode·图论
程序 代码狂人8 小时前
切片表与分区表的区别(数据开发面试版)
java·大数据·开发语言·数据仓库·算法
HDU-Dade9 小时前
【校招笔试真题】简要介绍 Self-Attention 的前沿算法
人工智能·算法
Xin77010 小时前
LeetCode 79. 单词搜索(DFS 回溯法)
leetcode
小郎君65811 小时前
Vue keep-alive 切标签后滚动位置回顶?因为 onDeactivated 里读到的 scrollTop 是 0
算法
邵奈一11 小时前
GPT-6.1 Terra速度是Sol的3倍,价格减半
算法
RaaS10011 小时前
Node.js Brotli RCE 漏洞自查指南:fetch、undici、axios 都在影响面,三分钟确认你的版本
人工智能·深度学习·算法
shehuiyuelaiyuehao12 小时前
算法56,重排链表
数据结构·算法·链表
qq_4523962312 小时前
第四篇:《索引原理与实战:B-tree、Hash、GIN、GiST、BRIN》
算法·哈希算法·gin