leetcode #121 买卖股票的最佳时机 | 刷题之路第二站——动态规划类问题

题号 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。

 

解题思路一——暴力法(超出时间限制)

数组的第 i 个元素表示该顾飘第 i 天的价格,假设我们在第 i 天买入该股票,分别计算第 i +1 天~第 n 天卖出可获得利润,取其中最大的利润记为 ans。

令 i 依次为 0 ~ n,重复上述过程,最后 ans 就是我们需要的结果。

代码如下:

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

时间复杂度:O(n^2)

空间复杂度:O(1)

 

解题思路二(超出时间限制)

使用数组 p 来记录每一天卖出可获得的最大利润值,比如 p[ i ] 表示第 i 天卖出股票时,可获得的最大利润值。

在计算 p[ i ] 时,取给定数组的前 i 个元素中的最小值,如果最小值大于第 i 个元素的值,则 p[ i ] = 0;否则 p [ i ] = 第 i 个元素的值 - 最小值。

最后取数组 p 中的最大值即可。

代码如下:

class Solution {
public:
	int maxProfit(vector<int>& prices) {
		int n = prices.size();
		vector<int> p(n);
		if (n == 0)
			return 0;
		if (n == 1)
			return 0;
		p[0] = 0;
		for (int i = 1; i < n; i++) {
			int minPrice = *min_element(prices.begin(), prices.begin() + i);
			if (minPrice > prices[i])
				p[i] = 0;
			else
				p[i] = prices[i] - minPrice;
		}
		return *max_element(p.begin(), p.end());
	}
};

时间复杂度:O(n^2)

空间复杂度:O(n)

 

解题思路三——动态规划解题

Step1、2:描述问题的最优解结构特征,递归定义最优解值

设 p[ i ] 表示第 i 天卖出股票时所能获取的最大利润,题目中给定的数组命名为 prices,显然 p[ i ] = prices[ i ] - 前 i -1个元素中的最小值。

假设前 i - 1 个元素的最小值为 minVal,显然有 p[ i - 1 ] = prices[ i - 1 ] - minVal

则:minVal = prices[ i - 1] - p[ i - 1 ]

所以 p[ i ] = max { p[ i - 1]  + prices[ i ] - prices[ i - 1 ] , 0 }

 

Step3、4:自底向上计算最优解值、输出最优解值

问题的底为:p[ 0 ] = 0

为了节省空间,我们可以不使用数组来存储每天卖出顾飘所能获取的最大利润,而是使用两个变量 F_i 和 F_i_1进行迭代,同时使用 maxVal 记录前 i 天中卖出股票可获取的最大利润值。【值得借鉴!!!】

循环结束后,maxVal 就是我们所要求的结果。

代码如下:

class Solution {
public:
	int maxProfit(vector<int>& prices) {
		if (!prices.size())
			return 0;

		int maxVal = 0;
		int Fi_1 = 0, Fi = 0;
		for (int i = 1; i < prices.size(); i++) {
			Fi = max(Fi_1 + prices[i] - prices[i - 1], 0);
			maxVal = max(Fi, maxVal);
			Fi_1 = Fi;
		}
		return maxVal;
	}
};

时间复杂度:O(n)

空间复杂度:O(1)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值