在每日股票交易中,买方在早上购买股票并在同一天卖出。如果允许交易者在一天内最多进行 2 笔交易,而第二笔交易只能在第一笔交易完成后开始(卖出->买入->卖出->买入)。给定全天的股票价格,找出股票交易者可能获得的最大利润。
例子:
Input: price[] = {10, 22, 5, 75, 65, 80}
Output: 87
Trader earns 87 as sum of 12, 75
Buy at 10, sell at 22,
Buy at 5 and sell at 80
Input: price[] = {2, 30, 15, 10, 8, 25, 80}
Output: 100
Trader earns 100 as sum of 28 and 72
Buy at price 2, sell at 30, buy at 8 and sell at 80
Input: price[] = {100, 30, 15, 10, 8, 25, 80};
Output: 72
Buy at price 8 and sell at 80.
Input: price[] = {90, 80, 70, 60, 50}
Output: 0
Not possible to earn.
一个简单的解决方案是考虑每个索引“i”并执行以下操作
Max profit with at most two transactions =
MAX {max profit with one transaction and subarray price[0..i] +
max profit with one transaction and subarray price[i+1..n-1] }
i varies from 0 to n-1.
可以使用以下 O(n) 算法计算使用一笔交易的最大可能
两个元素之间的最大差异,使得较大的元素出现在较小的数字之后
上述简单解决方案的时间复杂度为 O(n 2 )。
我们可以使用以下Efficient Solution来完成这个 O(n)。其思想是存储每个子数组的最大可能利润,并分以下两个阶段解决问题。
1)创建一个表progress[0..n-1]并将其中的所有值初始化为0。
2)从右到左遍历 price[] 并更新利润 [i],使得利润 [i] 将一笔交易可获得的最大利润存储在子数组 price[i..n-1] 中
3)从左到右遍历 price[] 并更新利润 [i],使得利润 [i] 存储最大利润,使得利润 [i] 包含子数组 price[0..i] 中两次交易的最大可实现利润。
4)返利[n-1]
要进行第 2 步,我们需要从右到左跟踪最高价格,而要进行第 3 步,我们需要从左到右跟踪最低价格。为什么我们要逆向穿越?这个想法是为了节省空间,在第三步中,我们为这两个目的使用相同的数组,最多 1 个事务,最多 2 个事务。在迭代 i 之后,数组利润 [0..i] 包含 2 笔交易的最大利润,而利润 [i+1..n-1] 包含两笔交易的利润。
下面是上述想法的实现。
C++
// C++ program to find maximum
// possible profit with at most
// two transactions
#include
using namespace std;
// Returns maximum profit with
// two transactions on a given
// list of stock prices, price[0..n-1]
int maxProfit(int price[], int n)
{
// Create profit array and
// initialize it as 0
int* profit = new int[n];
for (int i = 0; i < n; i++)
profit[i] = 0;
/* Get the maximum profit with
only one transaction
allowed. After this loop,
profit[i] contains maximum
profit from price[i..n-1]
using at most one trans. */
int max_price = price[n - 1];
for (int i = n - 2; i >= 0; i--) {
// max_price has maximum
// of price[i..n-1]
if (price[i] > max_price)
max_price = price[i];
// we can get profit[i] by taking maximum of:
// a) previous maximum, i.e., profit[i+1]
// b) profit by buying at price[i] and selling at
// max_price
profit[i]
= max(profit[i + 1], max_price - price[i]);
}
/* Get the maximum profit with two transactions allowed
After this loop, profit[n-1] contains the result */
int min_price = price[0];
for (int i = 1; i < n; i++) {
// min_price is minimum price in price[0..i]
if (price[i] < min_price)
min_price = price[i];
// Maximum profit is maximum of:
// a) previous maximum, i.e., profit[i-1]
// b) (Buy, Sell) at (min_price, price[i]) and add
// profit of other trans. stored in profit[i]
profit[i] = max(profit[i - 1],
profit[i] + (price[i] - min_price));
}
int result = profit[n - 1];
delete[] profit; // To avoid memory leak
return result;
}
// Driver code
int main()
{
int price[] = { 2, 30, 15, 10, 8, 25, 80 };
int n = sizeof(price) / sizeof(price[0]);
cout << "Maximum Profit = " << maxProfit(price, n);
return 0;
}
Java
class Profit {
// Returns maximum profit
// with two transactions on a
// given list of stock prices,
// price[0..n-1]
static int maxProfit(int price[], int n)
{
// Create profit array
// and initialize it as 0
int profit[] = new int[n];
for (int i = 0; i < n; i++)
profit[i] = 0;
/* Get the maximum profit
with only one transaction
allowed. After this loop,
profit[i] contains
maximum profit from
price[i..n-1] using at most
one trans. */
int max_price = price[n - 1];
for (int i = n - 2; i >= 0; i--) {
// max_price has maximum
// of price[i..n-1]
if (price[i] > max_price)
max_price = price[i];
// we can get profit[i]
// by taking maximum of:
// a) previous maximum,
// i.e., profit[i+1]
// b) profit by buying
// at price[i] and selling
// at
// max_price
profit[i] = Math.max(profit[i + 1],
max_price - price[i]);
}
/* Get the maximum profit
with two transactions allowed
After this loop, profit[n-1]
contains the result
*/
int min_price = price[0];
for (int i = 1; i < n; i++) {
// min_price is minimum
// price in price[0..i]
if (price[i] < min_price)
min_price = price[i];
// Maximum profit is maximum of:
// a) previous maximum, i.e., profit[i-1]
// b) (Buy, Sell) at (min_price, price[i]) and
// add
// profit of other trans.
// stored in profit[i]
profit[i] = Math.max(
profit[i - 1],
profit[i] + (price[i] - min_price));
}
int result = profit[n - 1];
return result;
}
// Driver Code
public static void main(String args[])
{
int price[] = { 2, 30, 15, 10, 8, 25, 80 };
int n = price.length;
System.out.println("Maximum Profit = "
+ maxProfit(price, n));
}
} /* This code is contributed by Rajat Mishra */
Python
# Returns maximum profit with
# two transactions on a given
# list of stock prices price[0..n-1]
def maxProfit(price, n):
# Create profit array and initialize it as 0
profit = [0]*n
# Get the maximum profit
# with only one transaction
# allowed. After this loop,
# profit[i] contains maximum
# profit from price[i..n-1]
# using at most one trans.
max_price = price[n-1]
for i in range(n-2, 0, -1):
if price[i] > max_price:
max_price = price[i]
# we can get profit[i] by
# taking maximum of:
# a) previous maximum,
# i.e., profit[i+1]
# b) profit by buying at
# price[i] and selling at
# max_price
profit[i] = max(profit[i+1], max_price - price[i])
# Get the maximum profit
# with two transactions allowed
# After this loop, profit[n-1]
# contains the result
min_price = price[0]
for i in range(1, n):
if price[i] < min_price:
min_price = price[i]
# Maximum profit is maximum of:
# a) previous maximum,
# i.e., profit[i-1]
# b) (Buy, Sell) at
# (min_price, A[i]) and add
# profit of other trans.
# stored in profit[i]
profit[i] = max(profit[i-1], profit[i]+(price[i]-min_price))
result = profit[n-1]
return result
# Driver function
price = [2, 30, 15, 10, 8, 25, 80]
print "Maximum profit is", maxProfit(price, len(price))
# This code is contributed by __Devesh Agrawal__
C#
// C# program to find maximum possible profit
// with at most two transactions
using System;
class GFG {
// Returns maximum profit with two
// transactions on a given list of
// stock prices, price[0..n-1]
static int maxProfit(int[] price, int n)
{
// Create profit array and initialize
// it as 0
int[] profit = new int[n];
for (int i = 0; i < n; i++)
profit[i] = 0;
/* Get the maximum profit with only
one transaction allowed. After this
loop, profit[i] contains maximum
profit from price[i..n-1] using at
most one trans. */
int max_price = price[n - 1];
for (int i = n - 2; i >= 0; i--) {
// max_price has maximum of
// price[i..n-1]
if (price[i] > max_price)
max_price = price[i];
// we can get profit[i] by taking
// maximum of:
// a) previous maximum, i.e.,
// profit[i+1]
// b) profit by buying at price[i]
// and selling at max_price
profit[i] = Math.Max(profit[i + 1],
max_price - price[i]);
}
/* Get the maximum profit with two
transactions allowed After this loop,
profit[n-1] contains the result */
int min_price = price[0];
for (int i = 1; i < n; i++) {
// min_price is minimum price in
// price[0..i]
if (price[i] < min_price)
min_price = price[i];
// Maximum profit is maximum of:
// a) previous maximum, i.e.,
// profit[i-1]
// b) (Buy, Sell) at (min_price,
// price[i]) and add profit of
// other trans. stored in
// profit[i]
profit[i] = Math.Max(
profit[i - 1],
profit[i] + (price[i] - min_price));
}
int result = profit[n - 1];
return result;
}
// Driver code
public static void Main()
{
int[] price = { 2, 30, 15, 10, 8, 25, 80 };
int n = price.Length;
Console.Write("Maximum Profit = "
+ maxProfit(price, n));
}
}
// This code is contributed by nitin mittal.
PHP
= 0; $i--)
{
// max_price has maximum
// of price[i..n-1]
if ($price[$i] > $max_price)
$max_price = $price[$i];
// we can get profit[i] by
// taking maximum of:
// a) previous maximum,
// i.e., profit[i+1]
// b) profit by buying at
// price[i] and selling at
// max_price
if($profit[$i + 1] >
$max_price-$price[$i])
$profit[$i] = $profit[$i + 1];
else
$profit[$i] = $max_price -
$price[$i];
}
// Get the maximum profit with
// two transactions allowed.
// After this loop, profit[n-1]
// contains the result
$min_price = $price[0];
for ($i = 1; $i < $n; $i++)
{
// min_price is minimum
// price in price[0..i]
if ($price[$i] < $min_price)
$min_price = $price[$i];
// Maximum profit is maximum of:
// a) previous maximum,
// i.e., profit[i-1]
// b) (Buy, Sell) at (min_price,
// price[i]) and add
// profit of other trans.
// stored in profit[i]
$profit[$i] = max($profit[$i - 1],
$profit[$i] +
($price[$i] - $min_price));
}
$result = $profit[$n - 1];
return $result;
}
// Driver Code
$price = array(2, 30, 15, 10,
8, 25, 80);
$n = sizeof($price);
echo "Maximum Profit = ".
maxProfit($price, $n);
// This code is contributed
// by Arnab Kundu
?>
Javascript
C++
#include
using namespace std;
int main()
{
int price[] = { 2, 30, 15, 10, 8, 25, 80 };
int n = 7;
// adding array
int profit = 0;
// Initializing variable
// valley-peak approach
/*
80
/
30 /
/ \ 25
/ 15 /
/ \ /
2 10 /
\ /
8
*/
for (int i = 1; i < n; i++)
{
// traversing through array from (i+1)th
// position
int sub = price[i] - price[i - 1];
if (sub > 0)
profit += sub;
}
cout << "Maximum Profit=" << profit;
return 0;
}
// This code is contributed by RohitOberoi.
Java
import java.io.*;
import java.util.*;
class GFG {
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
int price[] = { 2, 30, 15, 10, 8, 25, 80 };
// adding array
int profit = 0;
// Initializing variable
// valley-peak approach
/*
80
/
30 /
/ \ 25
/ 15 /
/ \ /
2 10 /
\ /
8
*/
for (int i = 1; i < price.length; i++) {
// traversing through array from (i+1)th
// position
int sub = price[i] - price[i - 1];
if (sub > 0)
profit += sub;
}
System.out.print("Maximum Profit=" + profit);
}
}
C#
using System;
using System.Collections.Generic;
class GFG {
static void Main()
{
int[] price = { 2, 30, 15, 10, 8, 25, 80 };
// adding array
int profit = 0;
// Initializing variable
// valley-peak approach
/*
80
/
30 /
/ \ 25
/ 15 /
/ \ /
2 10 /
\ /
8
*/
for (int i = 1; i < price.Length; i++) {
// traversing through array from (i+1)th
// position
int sub = price[i] - price[i - 1];
if (sub > 0)
profit += sub;
}
Console.WriteLine("Maximum Profit=" + profit);
}
}
// This code is contributed by divyeshrabadiya07
Javascript
Maximum Profit = 100
上述解决方案的时间复杂度为 O(n)。
算法范式:动态规划
使用 Valley-Peak 方法还有另一种计算此问题的方法,即获取可变利润并将其初始化为零,然后每当初始位置值较大时从第 (i+1) 个位置遍历 price[] 数组比之前的值添加到可变利润中。
但是这种方法在这个问题中不起作用,你只能买卖一只股票两次。例如,如果 price [] = {2, 4, 2, 4, 2, 4}那么这个特定的方法将给出结果6而在这个给定的问题中你只能做两个交易所以答案应该是4 。因此,这种方法仅在我们有机会进行无限交易时才有效。
C++
#include
using namespace std;
int main()
{
int price[] = { 2, 30, 15, 10, 8, 25, 80 };
int n = 7;
// adding array
int profit = 0;
// Initializing variable
// valley-peak approach
/*
80
/
30 /
/ \ 25
/ 15 /
/ \ /
2 10 /
\ /
8
*/
for (int i = 1; i < n; i++)
{
// traversing through array from (i+1)th
// position
int sub = price[i] - price[i - 1];
if (sub > 0)
profit += sub;
}
cout << "Maximum Profit=" << profit;
return 0;
}
// This code is contributed by RohitOberoi.
Java
import java.io.*;
import java.util.*;
class GFG {
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
int price[] = { 2, 30, 15, 10, 8, 25, 80 };
// adding array
int profit = 0;
// Initializing variable
// valley-peak approach
/*
80
/
30 /
/ \ 25
/ 15 /
/ \ /
2 10 /
\ /
8
*/
for (int i = 1; i < price.length; i++) {
// traversing through array from (i+1)th
// position
int sub = price[i] - price[i - 1];
if (sub > 0)
profit += sub;
}
System.out.print("Maximum Profit=" + profit);
}
}
C#
using System;
using System.Collections.Generic;
class GFG {
static void Main()
{
int[] price = { 2, 30, 15, 10, 8, 25, 80 };
// adding array
int profit = 0;
// Initializing variable
// valley-peak approach
/*
80
/
30 /
/ \ 25
/ 15 /
/ \ /
2 10 /
\ /
8
*/
for (int i = 1; i < price.Length; i++) {
// traversing through array from (i+1)th
// position
int sub = price[i] - price[i - 1];
if (sub > 0)
profit += sub;
}
Console.WriteLine("Maximum Profit=" + profit);
}
}
// This code is contributed by divyeshrabadiya07
Javascript
Maximum Profit=100
时间和空间复杂度分别为 O(n) 和 O(1)。
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。