leetcode dp简单题练习

动态规划一般过程为:
在这里插入图片描述

题目:121. 买卖股票的最佳时机

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。

在这里插入图片描述
1.暴力求解:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int max=0,n=prices.size();
        for(int i=0;i<n;i++){
            for(int j=i+1;j<n;j++){
                if(prices[j]-prices[i]>max)
                    max=prices[j]-prices[i];
            }
        }

        return max;
    }
};
  1. 动态规划
    确定状态找到状态转移方程:
    如果在第i天出售股票,那么能获得的最大利润就是当前的价格减去前i-1天的最低值,所以我们可以记录购入时的最小值,得到其状态转移方程为:dp[i] = min(d[i-1],prices[i])。
    初始化:
    int dp[0]=prices[0], max = 0;
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n=prices.size();
        if(n<=1)
            return 0;
        int dp[n],max=0;
        dp[0]=prices[0];
        for(int i=1;i<n;i++)
        {
            dp[i]=(dp[i-1]<prices[i])?dp[i-1]:prices[i];
            max=(prices[i]-dp[i])>max?prices[i]-dp[i]:max;
        }
            return max;
    }
};

这里可以对内存优化,因为我们一直使用的是dp[i],所以可以用一个变量保存,就不用数组了。

int maxProfit(vector<int>& prices) {
        int n=prices.size();
        if(n<=1)
            return 0;
        int min,max=0;
        min=prices[0];
        for(int i=1;i<n;i++)
        {
            min=(min<prices[i])?min:prices[i];
            max=(prices[i]-min)>max?prices[i]-min:max;
        }

            return max;
    }

题目:70. 爬楼梯

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

在这里插入图片描述
1.确定状态
在爬到某一层台阶时前一步有两种方式,一种是走了一阶到达该台阶,一种是走了两阶到达该台阶。假设dp[i]表示到达第i层有多少种方式,那么从后往前看每次dp[i]都依赖于前面的状态。
2.转移方程
可以看出,首先是dp[i - 1],上i-1层楼梯,有dp[i - 1]种方法,那么再一步跳一个台阶不就是dp[i]了么。
还有就是dp[i - 2],上i-2层楼梯,有dp[i - 2]种方法,那么再一步跳两个台阶不就是dp[i]了么。那么dp[i]就是 dp[i - 1]与dp[i - 2]之和!转移方程即为dp[i] = dp[i - 1] + dp[i - 2] 。
3.初始条件和边界
dp[1]是到达第一个台阶只有1中方式,dp[2]是到达第二个台阶,可以走两次一步或者一次两步共2种方式。

int climbStairs(int n) {
        if (n <= 1) return n; // 因为下面直接对dp[2]操作了,防止空指针
        int dp[n+1];
        dp[1] = 1;
        dp[2] = 2;
        for (int i = 3; i <= n; i++) { // 注意i是从3开始的
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        return dp[n];
    }

题目:746. 使用最小花费爬楼梯

数组的每个下标作为一个阶梯,第 i 个阶梯对应着一个非负数的体力花费值 cost[i](下标从 0 开始)。
每当你爬上一个阶梯你都要花费对应的体力值,一旦支付了相应的体力值,你就可以选择向上爬一个阶梯或者爬两个阶梯。
请你找出达到楼层顶部的最低花费。在开始时,你可以选择从下标为 0 或 1 的元素作为初始阶梯。

在这里插入图片描述

class Solution {
public:
    int minCostClimbingStairs(vector<int>& cost) {
        int s=cost.size();
        int dp[s+1];
       dp[0]=cost[0],dp[1]=cost[1];
       for(int i=2;i<s;i++){
           dp[i]=dp[i-1]<dp[i-2]?cost[i]+dp[i-1]:cost[i]+dp[i-2];
       }
       dp[s]=dp[s-1]<dp[s-2]?dp[s-1]: dp[s-2];
       return dp[s];
    }
};

题目:1646. 获取生成数组中的最大值

给你一个整数 n 。按下述规则生成一个长度为 n + 1 的数组 nums :
nums[0] = 0
nums[1] = 1
当 2 <= 2 * i <= n 时,nums[2 * i] = nums[i]
当 2 <= 2 * i + 1 <= n 时,nums[2 * i + 1] = nums[i] + nums[i + 1]
返回生成数组 nums 中的 最大 值。

这个题分奇数偶数计算,也可以把奇数偶数合并起来计算,利用偶数mod2为0和向下取整计算、
在这里插入图片描述

int getMaximumGenerated(int n) {
            int dp[n+1];
            if(n==0)
                return 0;
            if(n==1)
                return 1;
            dp[0]=0,dp[1]=1;
            int max=1;
            for(int i=2;i<=n;i++){
                if(i%2==0)
                    dp[i]=dp[i/2];
                else
                    dp[i]=dp[(i-1)/2]+dp[(i+1)/2];
                if(dp[i]>max)
                    max=dp[i];
            }
            return max;
    }

合并后:

for(int i=2;i<=n;i++){
                dp[i] = dp[i / 2] + i % 2 * dp[i / 2 + 1];
                if(dp[i]>max)
                    max=dp[i];
            }

题目:LCS 01. 下载插件

小扣打算给自己的 VS code 安装使用插件,初始状态下带宽每分钟可以完成 1 个插件的下载。假定每分钟选择以下两种策略之一:
使用当前带宽下载插件
将带宽加倍(下载插件数量随之加倍)
请返回小扣完成下载 n 个插件最少需要多少分钟。
注意:实际的下载的插件数量可以超过 n 个

在这里插入图片描述
这个题最优解法是贪心,但也可以参考贪心的思想用dp做。这里参考了题解的dp思路。
设dp[i]表示下载第i个插件所需的最少时间,那么dp[i]可以从两种方式转变为来:

  1. 下载i-1个文件所需的最短时间 +1s,
  2. 能够下载i/2个文件所需的时间提升带宽 +1s
    (为了避免i为奇数时除以2由于向下取整的问题,所以先i+1)
    所以有dp[i] = min(dp[(i+1)/2],dp[i-1])+1
int leastMinutes(int n) {
        int dp[n+1];
        dp[0] = 0;dp[1] = 1;
        for(int i = 2;i<=n;i++){
            dp[i] = min(dp[(i+1)/2],dp[i-1])+1;    
        }
        return dp[n];
    }

题目:LCP 07. 传递信息

小朋友 A 在和 ta 的小伙伴们玩传信息游戏,游戏规则如下:
有 n 名玩家,所有玩家编号分别为 0 ~ n-1,其中小朋友 A 的编号为 0
每个玩家都有固定的若干个可传信息的其他玩家(也可能没有)。传信息的关系是单向的(比如 A 可以向 B 传信息,但 B 不能向 A 传信息)。
每轮信息必须需要传递给另一个人,且信息可重复经过同一个人
给定总玩家数 n,以及按 [玩家编号,对应可传递玩家编号] 关系组成的二维数组 relation。返回信息从小 A (编号 0 ) 经过 k 轮传递到编号为 n-1 的小伙伴处的方案数;若不能到达,返回 0。

在这里插入图片描述
这道题没想出来,贴下官方解法:
在这里插入图片描述

class Solution {
public:
    int numWays(int n, vector<vector<int>>& relation, int k) {
        vector<vector<int>> dp(k + 1, vector<int>(n));
        dp[0][0] = 1;
        for (int i = 0; i < k; i++) {
            for (auto& edge : relation) {
                int src = edge[0], dst = edge[1];
                dp[i + 1][dst] += dp[i][src];
            }
        }
        return dp[k][n - 1];
    }
};

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/chuan-di-xin-xi/solution/chuan-di-xin-xi-by-leetcode-solution/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值