2.动态规划设计:最长递增子序列
dp数组的遍历方向
我相信读者做动态规划问题时,肯定会对dp数组的遍历顺序有些头疼。我们拿二维dp数组来举例,有时候我们是正向遍历:
//正向遍历
int[][] dp = new int[m][n];
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
// 计算 dp[i][j]
//有时候也会反向遍历
for (int i = m - 1; i >= 0; i--)
for (int j = n - 1; j >= 0; j--)
// 计算 dp[i][j]
// 斜着遍历数组
for (int l = 2; l <= n; l++) {
for (int i = 0; i <= n - l; i++) {
int j = l + i - 1;
// 计算 dp[i][j]
}
}
那么,如果仔细观察的话可以发现其中的原因的。你只要把住两点就行了:
1、遍历的过程中,所需的状态必须是已经计算出来的。
2、遍历的终点必须是存储结果的那个位置。
最长递增子序列(LeetCode 300题 难度:中等)

动态规划的核心就是数学归纳法
先假设这个结论在k<N时候成立,那么根据这个假设,在想办法,推出在k=N时结论也成立,如果能够证明出来,那么对于任意的k 就都成立了
难点:定义清楚dp数组到底代表什么?
我们这样定义:dp[i]表示以nums[i]这个数字结尾的最长递增子序列
解释:
现在我们想求dp[5]的值,那么也就是要求以nums[5]为结尾的这个数的最长递增子序列
nums[5]=3,既然是递增子序列,只要找到前面那么结尾比3小的子序列,然后把3接到最后面,就可形成新的递增子序列,而且长度要+1;
//初始条件
// 因为最小 是 1
Arrays.fill(dp,1);
for (int i = 0; i < nums.length; i++) {
for (int j = 0; j < i; j++) {
if(nums[i]>nums[j]){
//求 nums[5]的递增子序列,只需要找到5前面的某个 比5小的数字的 子序列然后 +1(自己)
//找第五个数的递增子序列,只需要找到 前面比5小的那个数字的 递增子序列 然后 +自己
dp[i]=Math.max(dp[i],dp[j]+1);
}
}
//保存一下递增子序列的最大值
res=Math.max(dp[i],res);
}

浙公网安备 33010602011771号