[LeetCode]Best Time to Buy and Sell Stock做题笔记

1、Best Time to Buy and Sell Stock

题意:给定一个数组,该数组为每天股票的价格,求解出你最大的收益是多少(哪一天买,哪一天卖可以获得最多的盈利),最多只能持有一笔交易。

分析:该题目可以转化为求最大和的类型,后面一天减去前面一天的股价,即可得到两天之间的收益,求出该收益序列的连续子序列最大和即可。

临界条件:如果数组只有一个元素,表示收益为0;如果计算出的收益为负数,依然返回0.

代码:

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

还有另外一种思路,要求最大的收益,自然是用最高的股票价格减去最低的价格即可,考虑到时间的因素,当前的收益一定是当天价格减去前面几天里的最低价格即可。

所以产生了如下代码:

    int maxProfit(vector<int> &prices) {

        if(prices.size() < 1)
        {
            return 0;
        }
        int minVal = prices[0];
        int max = 0;
        for(int i = 1; i < prices.size(); ++i)
        {
            max = max > prices[i] - minVal ? max : prices[i]-minVal;
            minVal = minVal < prices[i] ? minVal : prices[i];
        }
        
        return max > 0 ? max : 0;
    }

2、Best Time to Buy and Sell Stock I

题意:给定条件同1,只是可以进行任意多的交易,不限交易次数,但是同时进行的交易只能有一个
分析:该题目只要理解了题意,就很简单,可以进行任意笔的交易,则就是把相邻两天收益为正数的累加即可。
边界条件:同1
代码:
    int maxProfit(vector<int> &prices) {
        if(prices.size() <= 1)
        {
            return 0;
        }
        int max = 0;
        for(int i = 0; i < prices.size()-1; ++i)
        {
            int element = prices[i+1]-prices[i];
            if(element > 0)
            {
                max += element;
            }
        }
        return max > 0 ? max : 0;
    }

3、Best Time to Buy and Sell Stock II

题意:本题目的限制条件修改为最多只能进行两次交易,两次交易时间不能有重叠

分析:这一题的难度提升,此问题可以分解为两个子问题:假设要计算第5天的收益,则可以分解为第5天之前的最大收益与第5天之后的最大收益,两者相加,则为以第5天作为第一次交易与第二次交易的临界,所得的最大收益,如果知道给定数组里每一天的最大收益,其中最大的那个即为数组内所有天数里的收益最大值。

起初,借鉴编程之美中,求子序列最大和的思想,写出了如下代码:

 

class Solution {
public:
	int maxProfit(vector<int> &prices) {
		// Start typing your C/C++ solution below
		// DO NOT write int main() function
		if(prices.size() < 2)
		{
			return 0;
		}
		if(prices.size() == 2)
		{
			return prices[1]-prices[0] > 0 ? prices[1]-prices[0] : 0;
		}

		vector<int> sub_pris = vector<int>();

		for (int i = 0; i < prices.size()-1; ++i)
		{
			sub_pris.push_back(prices[i+1]-prices[i]);
		}
		int num = sub_pris.size();
		vector<int> all;
		all.resize(num);

		all[0] = sub_pris[0];
		int last = sub_pris[0];
		for(int i = 1; i < sub_pris.size(); ++i)
		{
			last = max(sub_pris[i], last+sub_pris[i]);
			all[i] = max(all[i-1], last);
		}

		int ret_max = 0;
		int before = sub_pris[num-1];
		int start = sub_pris[num-1];
		for(int i = num - 2; i >= 0; --i)
		{
			start = max(sub_pris[i], start+sub_pris[i]);
			before = max(start, before);
			int curall = i >= 1?all[i-1]:0;
			if(before + curall > ret_max)
				ret_max = before + curall;
		}
		return ret_max>0?ret_max:0;

	}

	int max(int a, int b)
	{
		return a > b ? a : b;
	}      
};


上面代码中,先求出相邻天的收益数组,然后分别从左向右、从右向左求出子序列最大和,逻辑清晰,但是实现稍微复杂一些。

借鉴第一小节的方法,写出了代码2,相对与上面的代码,逻辑比较清晰一些。

	int maxProfit(vector<int> &prices) {
		if(prices.size() < 2)
		{
			return 0;
		}
		if(prices.size() == 2)
		{
			return prices[1]-prices[0] > 0 ? prices[1]-prices[0] : 0;
		}

		vector<int> all;
		all.resize(prices.size()-1);
		int minVal = prices[0];
		for(int i = 1; i < prices.size(); ++i)
		{
			int tmpmax = i>=2?all[i-2]:0;
			if(prices[i] - minVal > tmpmax)
				all[i-1] = prices[i]-minVal;
			else
				all[i-1] = tmpmax;

			if(minVal > prices[i])
				minVal = prices[i];
		}

		int maxVal = prices[prices.size()-1];
		int max = 0;
		int ret_max = 0;
		for(int i = prices.size()-2; i >= 0; --i)
		{
			max = maxVal - prices[i] > max ? maxVal - prices[i] : max;            
            		int cmp = max;
			if(i >= 1)
			{
			    cmp += all[i-1];
    			}
    			if(ret_max < cmp)
				ret_max = cmp;	

            		if(prices[i] > maxVal)
               		 	maxVal = prices[i];
		}
		return ret_max>0?ret_max:0;
	}

以上代码在LeetCode中可通过所有的test case,发出来供大家参考。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: LeetCode 的第一题是 Two Sum。题目描述是:给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那两个整数,并返回他们的数组下标。 解法: 1. 暴力枚举法:对于每一个数,遍历整个数组,找到另一个数使得它们的和为 target。时间复杂度为 O(n^2)。 2. Hash 表法:遍历数组,对于每一个数,用 target 减去该数,判断差值是否在数组中出现过,如果出现过就返回该数的下标和差值的下标。时间复杂度为 O(n)。 在 LeetCode 中,你可以使用任意一种方法来解决该题。 ### 回答2: leetcode第一题是要求找出数组中两个数的和等于给定目标数的索引。可以使用哈希表来解决这个问题。 首先,我们可以创建一个空的哈希表。然后,遍历整个数组,对于每一个元素,计算目标数减去当前元素的差值。接着,我们检查差值是否在哈希表中,如果存在,说明当前元素与差值的和等于目标数。我们可以直接返回当前元素和差值在哈希表中的索引。 如果差值不在哈希表中,我们将当前元素及其索引插入哈希表中,以便之后可以通过差值来找到当前元素的索引。遍历完成后,如果没有找到满足条件的索引,返回一个空数组或者其他指定的结果。 使用哈希表的解决方案可以将查找的时间复杂度降低到O(1)。整个算法的时间复杂度为O(n),其中n为数组的长度。算法的空间复杂度为O(n),因为需要额外的哈希表来存储元素及其索引。 总结起来,leetcode第一题可以通过使用哈希表来解决,其中遍历数组并将元素及其索引存储在哈希表中,然后查找差值是否在哈希表中,找到满足条件的索引并返回。这个解决方案的时间复杂度为O(n),空间复杂度为O(n)。 ### 回答3: LeetCode是一个在线的编程题库,第一题是非常简单的算法题。这个题目要求我们在一个整数数组中找到两个数,使得它们的和等于目标数。解决这个问题有几种方法。 一种简单的方法是使用双重循环来遍历数组中的每一对数,然后判断它们的和是否等于目标数。这样的时间复杂度是O(n^2),不是很高效。 另一种更优化的方法是使用哈希表。我们可以遍历一遍数组,将每个数与目标数的差值作为键,对应的索引作为值存放在哈希表中。然后再次遍历数组,每次都判断当前数在哈希表中是否存在,如果存在则说明找到了满足条件的两个数。这种方法的时间复杂度是O(n),空间复杂度也是O(n)。 还有一种更巧妙的方法是使用双指针。我们可以设置两个指针,一个指向数组的起始位置,一个指向数组的末尾位置,然后通过移动指针来逐渐缩小搜索范围。如果指针所指的两个数的和等于目标数,则找到了答案;如果和小于目标数,则将左指针右移一位;如果和大于目标数,则将右指针左移一位。这种方法的时间复杂度也是O(n),但空间复杂度是O(1),比哈希表方法更节省空间。 总之,这个题目虽然很简单,但是解决的方法有多种。根据题目要求和具体情况,我们可以选择适合的方法来解决这个问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值