zoukankan      html  css  js  c++  java
  • 算法学习 —— 动态规划练习(一)

    一、买卖股票的最佳时机(LeetCode-121)

    1.1 题目介绍

    121. 买卖股票的最佳时机

    给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
    
    如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。
    
    注意你不能在买入股票前卖出股票。
    
    示例 1:
    
    输入: [7,1,5,3,6,4]
    输出: 5
    解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
         注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。
    示例 2:
    
    输入: [7,6,4,3,1]
    输出: 0
    解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
    
    

    1.2 解题思路

    想要利润最大,尽可能地要保证购买的时候价格最低,总利润最高。由此可以列出状态转移方程。

    buy = min{buy,price}
    profilt = max{profilt,price-buy}

    1.3 解法

        public int maxProfit(int[] prices) {
            int profilt = 0;
            int buy = Integer.MAX_VALUE;
            for (int price : prices) {
                buy = Math.min(buy, price);
                profilt = Math.max(profilt, price - buy);
            }
            return profilt;
        }
    

    二、使用最小花费爬楼梯(LeetCode-746)

    2.1 题目介绍

    数组的每个索引做为一个阶梯,第 i个阶梯对应着一个非负数的体力花费值 costi

    每当你爬上一个阶梯你都要花费对应的体力花费值,然后你可以选择继续爬一个阶梯或者爬两个阶梯。

    您需要找到达到楼层顶部的最低花费。在开始时,你可以选择从索引为 0 或 1 的元素作为初始阶梯。

    示例 1:
    输入: cost = [10, 15, 20]
    输出: 15
    解释: 最低花费是从cost[1]开始,然后走两步即可到阶梯顶,一共花费15。

    示例 2:
    输入: cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1]
    输出: 6
    解释: 最低花费方式是从cost[0]开始,逐个经过那些1,跳过cost[3],一共花费6。
    注意:
    cost 的长度将会在 [2, 1000]。
    每一个 cost[i] 将会是一个Integer类型,范围为 [0, 999]。

    2.2 解题思路

    以样本为例cost = [10, 15, 20]
    n = 3;

    最后一步:
    根据题意我们知道,最后一步不一定是cost[2](即20),还有可能是之后的值,我们这里假设有cost[3]且cost[3] = 0,这里我们就统一认为最后一步是cost[3],因为它的需要用的体力值设置为0。所以最后走到cost[2]所用的总体力值,和走到cost[3]的是一样的。

    子问题
    最后一步消耗的体力值是cost[3],总共消耗的体力值为f[3]。
    走到了最后一步之后,往前回退,所面对的选择是,要么是倒退一步,要么是倒退两步。

    于是有了子问题方程:

    f[3] = min(f[1],f[2])+cost[3]

    状态转移方程

    f[x] = min(f[x-1],f[x-2])+cost[x]

    初始条件
    第一步可以从cost[0]开始走,也可以从cost[1]开始走。于是有了
    f[0] = cost[0]
    f[1] = cost[1]

    边界
    int costLength = cost.length;
    cost[costLengh+1] = 0
    f[costLengh+1]为最终的解。

    2.3 解法

    
    public int minCostClimbingStairs(int[] cost) {
    
            int n = cost.length;
            int[] f = new int[n+1];
            //初始化
            f[0] = cost[0];
            f[1] = cost[1];
            for (int i = 2; i <= n; i++) {
                int tempCost = 0;
                if (i == n) {
                	//cost[n] = 0
                    tempCost = 0;
                } else {
                    tempCost = cost[i];
                }
                f[i] = Math.min(f[i - 1], f[i - 2]) + tempCost;
            }
            return f[n];
        }
    
    

    三、爬楼梯(LeetCode-70)

    3.1 题目介绍

    70. 爬楼梯

    假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

    每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
    注意:给定 n 是一个正整数。

    示例 1:
    输入: 2
    输出: 2
    解释: 有两种方法可以爬到楼顶。

    1. 1 阶 + 1 阶
    2. 2 阶

    示例 2:
    输入: 3
    输出: 3
    解释: 有三种方法可以爬到楼顶。

    1. 1 阶 + 1 阶 + 1 阶
    2. 1 阶 + 2 阶
    3. 2 阶 + 1 阶

    3.2 解题思路

    最后一步:

    最后一步是第n个台阶,我们这边假设为4。

    子问题
    最后一步到第4个台阶,假设总共有走法f[4]。
    如果是走到第3个台阶的话,就只能再走1步
    如果走到第2个台阶的话,可以走2步,或者走2次,分别走1步。

    于是有了子问题方程:

    f[4] = f[4-step1] + f[4-step2]
    f[4] = f[3] + f[2]

    状态转移方程

    f[x] = f[x-1] + f[x-2]

    3.3 解法

    
    class Solution {
        public int climbStairs(int n) {
            int[] f = new int[n+1];
            if(n<=2){
                return n;
            }
            //初始化
            f[0] = 0;
            f[1] = 1;
            f[2] = 2;
            //f[x] = f[x-1] + f[x-2]
            for(int i=3;i<=n;i++){
                f[i] = f[i-1]+f[i-2];
            }
            return f[n];
            
        }
    }
    
    

    四、最大子序和(LeetCode-53)

    4.1 题目介绍

    给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

    示例:
    输入: [-2,1,-3,4,-1,2,1,-5,4],
    输出: 6
    解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
    进阶:

    如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。

    4.2 解题思路

    分析能不能使用DP,要考虑符不符合DP的子问题重叠,即一个子问题,依赖于上一个子问题

    简化输入,只有-2,则dp[0] 为最大子序列和,dp[0] = -2,

    假设只有,-2,1,则dp[1]会参考dp[0],会比较1与-2+1的大小,从而确定要不要前面的-2,由此可得出

    $dp[i] = max{ dp[i-1]+nums[i],nums[i]} $

    4.3 解法

    
    public static int maxSubArray(int[] nums) {
            // dp[i] = max(dp[i-1]+nums[i],nums[i])
            int[] dp = new int[nums.length];
            dp[0] = nums[0];
            int res = dp[0];
            for (int i = 1; i < nums.length; i++) {
                dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]);
                res = res > dp[i] ? res : dp[i];
            }
            return res;
        }
    
    

    参考文档

    LeetCode中动态规划题解合集

  • 相关阅读:
    Apache配置虚拟主机的三种方法(基于IP、端口、域名)
    shell中嵌套执行expect命令实例(利用expect实现自动登录)
    Shell脚本实现SSH免密登录及批量配置管理
    搭建本地yum源服务器
    awk之腾迅面试题1
    16个tomcat面试题
    tomcat常见面试题1
    Mysql经典面试题
    10个超有趣的linux命令
    Codeforces Beta Round #79 (Div. 2 Only)
  • 原文地址:https://www.cnblogs.com/fonxian/p/10854655.html
Copyright © 2011-2022 走看看