[LeetCode] 188. Best Time to Buy and Sell Stock IV

本文深入探讨了股票交易策略的算法设计,通过动态规划与贪心算法解决LeetCode上“最佳买卖股票时机”系列问题,特别是在允许多次交易的场景下。文章详细解析了如何优化算法以避免内存限制错误,以及当交易次数不受限时采用贪心算法的高效解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原题链接: https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iv/

Buy and Sell Stock专题相关题目

121. Best Time to Buy and Sell Stock
122. Best Time to Buy and Sell Stock II
123. Best Time to Buy and Sell Stock III
188. Best Time to Buy and Sell Stock IV
309. Best Time to Buy and Sell Stock with Cooldown
714. Best Time to Buy and Sell Stock with Transaction Fee

1. 题目介绍

Say you have an array for which the ith element is the price of a given stock on day i.

Design an algorithm to find the maximum profit. You may complete at most k transactions.

Note:
You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).

输入一个数组,数组中第 i 个数代表着某只股票在第 i 天的价格,最多交易为k次,求可获得的最大利润。必须先买后卖,并且同一天只能买一次或者卖一次二选一,不能在同一天买卖。

Example 1:

Input: [2,4,1], k = 2
Output: 2
Explanation: Buy on day 1 (price = 2) and sell on day 2 
(price = 4), profit = 4-2 = 2.
Example 2:

Input: [3,2,6,5,0,3], k = 2
Output: 7
Explanation:
Buy on day 2 (price = 2) and sell on day 3 (price = 6), 
profit = 6-2 = 4.

Then buy on day 5 (price = 0) and sell on day 6 (price = 3), 
profit = 3-0 = 3.

2. 解题思路

动态规划法

这个题是上一道题 123. Best Time to Buy and Sell Stock III的改进版,在III中,只允许最多交易2次,而在IV中就不限次数了,可以不限次数交易。

根据 123. Best Time to Buy and Sell Stock III的解题方法,我们把那一题的代码稍作更改,加入了k次这个变量。

class Solution {
   public int maxProfit(int k, int[] prices) {
		int length = prices.length;
	    if(prices==null || length==0)
	        return 0;
	    
	    
	    int[] local = new int[k+1];
	    int[] global = new int[k+1];
	    
	    for(int i = 1; i<length ; i++)
	    {
	        int diff = prices[i]-prices[i-1];

	        for(int j=k;j>=1;j--)
	        {
	        	local[j] = Math.max(global[j-1]+(diff>0?diff:0) , local[j]+diff);
	            global[j] = Math.max( local[j] , global[j] );
	        }
	    }
	    return global[k];
	}
}

提交的结果如何呢?Memory Limit Exceeded !
在这里插入图片描述
这个样例中,k和数组都很大,该怎么解决呢?

优化方法1

首先看k,在这个样例中,k很大,这就会导致上述代码中的

for(int j=k;j>=1;j--)
{
	local[j] = Math.max(global[j-1]+(diff>0?diff:0) , local[j]+diff);
	global[j] = Math.max( local[j] , global[j] );
}

执行非常漫长。因此,我们需要做出第一个优化,当k的值超过最大交易次数时,我们就要把k换成最大交易次数,提高效率。数组中共有 n 个数,每个数只能买,或者卖,二选一。买卖一次算是交易,因此最大的交易次数是 n/2

当k > n/2时,我们就把n/2赋值给k,改进后的提交就成功了。

实现代码

class Solution {
   public int maxProfit(int k, int[] prices) {
		int length = prices.length;
	    if(prices==null || length==0)
	        return 0;
	    
	    if(k > length/2) {
	    	k = length/2;
	    }
	    
	    int[] local = new int[k+1];
	    int[] global = new int[k+1];
	    
	    for(int i = 1; i<length ; i++)
	    {
	        int diff = prices[i]-prices[i-1];

	        for(int j=k;j>=1;j--)
	        {
	        	local[j] = Math.max(global[j-1]+(diff>0?diff:0) , local[j]+diff);
	            global[j] = Math.max( local[j] , global[j] );
	        }
	    }
	    return global[k];
	}
}

耗时95ms
在这里插入图片描述

优化方法2

当k的值超过最大交易次数时,同时意味着,可以无限次交易了。那样就可以使用贪心的方法,从头遍历数组,每当遇到prices[ i ] > prices[i-1]时,就可以将差价算为收入。

这样的改进方法最后也成功了,而且执行时间非常短。

实现代码

class Solution {
   public int maxProfit(int k, int[] prices) {
		int length = prices.length;
	    if(prices==null || length==0)
	        return 0;
	    
	    if(k > length/2) {
	    	int ans = 0;
	    	for(int i = 1;i<length;i++) {
	    		if(prices[i] > prices[i-1]) {
	    			ans += prices[i] - prices[i-1];
	    		}
	    	}
	    	return ans;
	    }
	    
	    int[] local = new int[k+1];
	    int[] global = new int[k+1];
	    
	    for(int i = 1; i<length ; i++)
	    {
	        int diff = prices[i]-prices[i-1];

	        for(int j=k;j>=1;j--)
	        {
	        	local[j] = Math.max(global[j-1]+(diff>0?diff:0) , local[j]+diff);
	            global[j] = Math.max( local[j] , global[j] );
	        }
	    }
	    return global[k];
	}
}

执行时间只需3ms
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值