动态规划——20200102

4 最长上升子序列
4.1 题目描述
给定一个无序的整数数组,找到其中最长上升子序列的长度。

示例:
输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。

说明:
可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
你算法的时间复杂度应该为 O(n2) 。
4.2 分析
动态规划的核心设计思想是数学归纳法。
相信大家对数学归纳法都不陌生,高中就学过,而且思路很简单。比如我们想证明一个数学结论,那么我们先假设这个结论在 k<n 时成立,然后想办法证明 k=n 的时候此结论也成立。如果能够证明出来,那么就说明这个结论对于 k 等于任何数都成立。
直接拿最长递增子序列这个问题举例你就明白了。不过,首先要定义清楚 dp 数组的含义,即 dp[i] 的值到底代表着什么?
我们的定义是这样的:dp[i] 表示以 nums[i] 这个数结尾的最长递增子序列的长度。
例如:

在这里插入图片描述
在这里插入图片描述
Ok,现在知道了dp[0] – dp[4],怎样计算dp[5]?
在这里插入图片描述
现在想求 dp[5] 的值,也就是想求以 nums[5] 为结尾的最长递增子序列。
nums[5] = 3,既然是递增子序列,我们只要找到前面那些结尾比 3 小的子序列,然后把 3 接到最后,就可以形成一个新的递增子序列,而且这个新的子序列长度加一。

当然,可能形成很多种新的子序列,但是我们只要最长的,把最长子序列的长度作为 dp[5] 的值即可。
4.3 代码
int max(int a, int b) {
return a > b ? a : b;
}

//dp[i]表示以nums[i]为结尾,最长的上升子序列长度
int lengthOfLIS(int* nums, int numsSize){
if(numsSize <= 0) {
return 0;
}
if(numsSize == 1) {
return 1;
}

int i = 0, j = 0;
int result = INT_MIN;
int dp[numsSize]; 
for(i = 0; i < numsSize; i++) {
    dp[i] = 1; //初始化为1,每个对于数字,至少是1
}
result = dp[0];

for(i = 1; i < numsSize; i++) {
    for(j = 0; j < i; j++) {   //对于每一个以nums[i]结尾的数组,都要看它前面所有的比它小的
        if(nums[i] > nums[j]) {
            dp[i] = max(dp[j] + 1, dp[i]);   //这里和自身取大值的的意思是要比较前面所有的比它自身小的
        }
    }
    result = result > dp[i] ? result : dp[i];
}

return result;

}

https://labuladong.gitbook.io/algo/dong-tai-gui-hua-xi-lie/dong-tai-gui-hua-she-ji-zui-chang-di-zeng-zi-xu-lie

发布了39 篇原创文章 · 获赞 1 · 访问量 856

猜你喜欢

转载自blog.csdn.net/weixin_42268479/article/details/103805583