📌  相关文章
📜  最多两次买卖股票的最大利润

📅  最后修改于: 2021-09-17 06:46:14             🧑  作者: Mango

在每日股票交易中,买方在早上购买股票并在同一天卖出。如果允许交易者在一天内最多进行 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 现场工作专业课程学生竞争性编程现场课程