算法精讲:动态规划

在这里插入图片描述

介绍

动态规划并不是一种具体的算法,而是一种思想,个人觉得就是缓存+枚举,把求解的问题分成许多阶段或者多个子问题,然后按顺序求解各子问题。前一子问题的解为后一子问题提供了有用的信息。在求解任一子问题时,列出各种可能的局部解,通过决策保留那些有可能达到最优的局部解,丢弃其他局部解。依次解决各子问题,最后一个子问题就是初始问题的解。

所以动态规划一般用来求最优解(对子问题进行决策),求种类数(对子问题进行加和)

先分享几个经典的动态规划实现,后续再分析几个面试题

最长上升子序列

来源:LeetCode 300.最长上升子序列
描述:给定一个无序的整数数组,找到其中最长上升子序列的长度。

示例:

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

可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
你算法的时间复杂度应该为 O(n2) 。
进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗?

思路:子序列有很多,最长的长度为4
在这里插入图片描述

我们假设dp[i]存的是到第i个元素时,数组的最长子序列,则对应的状态转移方程为

dp[i] = max{
   1, dp[j] + 1 | j < i 且 arr[j] < arr[i]}

其中1为只有自己一个元素,则递增子序列的长度为1

public class Solution {
   

    public int lengthOfLIS(int[] nums) {
   
        int max = 0;
        int[] dp = new int[nums.length];
        for (int i = 0; i < nums.length; i++) {
   
            dp[i] = 1;
            for (int j = 0; j < i; j++) {
   
                if (nums[i] > nums[j] && (dp[j] + 1) > dp[i]) {
   
                    dp[i] = dp[j] + 1;
                }
            }
            if (dp[i] > max) {
   
                max = dp[i];
            }
        }
        return max;
    }
}

数塔问题

来源:LeetCode 120. 三角形最小路径和
描述:给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。

相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。

例如,给定三角形:

[
     [2],
    [3,4],
   [6,5,7],
  [4,1,8,3]
]

自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)
说明:
如果你可以只使用 O(n) 的额外空间(n 为三角形的总行数)来解决这个问题,那么你的算法会很加分。

思路:把这个图形换一下,方便讲递推公式

[2],
[3,4],
[6,5,7],
[4,1,8,3]

在这里插入图片描述
我们可以从底到顶来算最优值。
dp[i][j]为从最底部到第i行第j列的最小路径和,value[i][j]为第i行第j列的值,状态转移方程为

dp[i][j] = max(dp[i-1][j-1], dp[i-1][j]) + triangle[i][j]
public class Solution {
   

    public int minimumTotal(List<List<Integer>> triangle) {
   
        if (triangle == null || triangle.size() == 0) {
   
            return 0;
        }
        // 这里行和列加1,是为了不用处理最下面一行的边界
        int[][] dp = new int[triangle.size() + 1][triangle.size() + 1];
        for (int i = triangle.size() - 1; i >= 0; i--) {
   
            List<Integer> rows = triangle.get(i);
            for (int j = 0; j < rows.size(); j++) {
   
                dp[i][j] 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值