📌  相关文章
📜  最多买入和卖出 k 次股票的最大利润

📅  最后修改于: 2021-09-17 07:38:54             🧑  作者: Mango

在股票交易中,买方买入股票并在未来日期卖出。给定n天的股票价格,交易者最多可以进行k笔交易,其中新交易只能在前一笔交易完成后开始,找出股票交易者可以获得的最大利润。
例子:

Input:  
Price = [10, 22, 5, 75, 65, 80]
    K = 2
Output:  87
Trader earns 87 as sum of 12 and 75
Buy at price 10, sell at 22, buy at 
5 and sell at 80

Input:  
Price = [12, 14, 17, 10, 14, 13, 12, 15]
    K = 3
Output:  12
Trader earns 12 as the sum of 5, 4 and 3
Buy at price 12, sell at 17, buy at 10 
and sell at 14 and buy at 12 and sell
at 15
 
Input:  
Price = [100, 30, 15, 10, 8, 25, 80]
    K = 3
Output:  72
Only one transaction. Buy at price 8 
and sell at 80.

Input:  
Price = [90, 80, 70, 60, 50]
    K = 1
Output:  0
Not possible to earn. 

该问题有多种版本。如果我们只允许买卖一次,那么我们可以使用两个元素之间的最大差值算法。如果我们最多允许进行 2 笔交易,我们可以按照这里讨论的方法进行。如果我们被允许买卖任意次数,我们可以遵循这里讨论的方法。

在这篇文章中,我们只允许最多进行 k 笔交易。这个问题可以用动态规划解决。
利润[t][i]表示使用最多 t 次交易直到第 i 天(包括第 i 天)的最大利润。那么关系是:
利润[t][i] = 最大值(利润[t][i-1], 最大值(价格[i] – 价格[j] + 利润[t-1][j]))
对于 [0, i-1] 范围内的所有 j
利润[t][i] 将是最大值 –

  1. 利润[t][i-1] 表示在第 i 天没有进行任何交易。
  2. 在第 i 天卖出获得的最大利润。为了在第 i 天卖出股票,我们需要在 [0, i – 1] 天中的任何一天买入。如果我们在第 j 天买入股票并在第 i 天卖出,最大利润将为 price[i] – price[j] + 利润 [t-1][j],其中 j 从 0 到 i-1 变化。这里的利润 [t-1][j] 是我们本可以在第 j 天之前减少一笔交易的最佳情况。

下面是基于动态规划的实现。

C++
// C++ program to find out maximum profit by
// buying and selling a share atmost k times
// given stock price of n days
#include 
#include 
using namespace std;
 
// Function to find out maximum profit by buying
// & selling a share atmost k times given stock
// price of n days
int maxProfit(int price[], int n, int k)
{
    // table to store results of subproblems
    // profit[t][i] stores maximum profit using
    // atmost t transactions up to day i (including
    // day i)
    int profit[k + 1][n + 1];
 
    // For day 0, you can't earn money
    // irrespective of how many times you trade
    for (int i = 0; i <= k; i++)
        profit[i][0] = 0;
 
    // profit is 0 if we don't do any transaction
    // (i.e. k =0)
    for (int j = 0; j <= n; j++)
        profit[0][j] = 0;
 
    // fill the table in bottom-up fashion
    for (int i = 1; i <= k; i++) {
        for (int j = 1; j < n; j++) {
            int max_so_far = INT_MIN;
 
            for (int m = 0; m < j; m++)
                max_so_far = max(max_so_far,
                                 price[j] - price[m] + profit[i - 1][m]);
 
            profit[i][j] = max(profit[i][j - 1], max_so_far);
        }
    }
 
    return profit[k][n - 1];
}
 
// Driver code
int main()
{
    int k = 2;
    int price[] = { 10, 22, 5, 75, 65, 80 };
    int n = sizeof(price) / sizeof(price[0]);
 
    cout << "Maximum profit is: "
         << maxProfit(price, n, k);
 
    return 0;
}


Java
// Java program to find out maximum
// profit by buying and selling a
// share atmost k times given
// stock price of n days
 
class GFG {
     
    // Function to find out
    // maximum profit by
    // buying & selling a
    // share atmost k times
    // given stock price of n days
    static int maxProfit(int[] price,
                         int n,
                         int k)
    {
         
        // table to store results
        // of subproblems
        // profit[t][i] stores
        // maximum profit using
        // atmost t transactions up
        // to day i (including day i)
        int[][] profit = new int[k + 1][n + 1];
 
        // For day 0, you can't
        // earn money irrespective
        // of how many times you trade
        for (int i = 0; i <= k; i++)
            profit[i][0] = 0;
 
        // profit is 0 if we don't
        // do any transaction
        // (i.e. k =0)
        for (int j = 0; j <= n; j++)
            profit[0][j] = 0;
 
        // fill the table in
        // bottom-up fashion
        for (int i = 1; i <= k; i++)
        {
            for (int j = 1; j < n; j++)
            {
                int max_so_far = 0;
 
                for (int m = 0; m < j; m++)
                max_so_far = Math.max(max_so_far, price[j] -
                             price[m] + profit[i - 1][m]);
 
                profit[i][j] = Math.max(profit[i] [j - 1],
                                              max_so_far);
            }
        }
 
        return profit[k][n - 1];
    }
 
    // Driver code
    public static void main(String []args)
    {
        int k = 2;
        int[] price = { 10, 22, 5, 75, 65, 80 };
        int n = price.length;
        System.out.println("Maximum profit is: " +
                            maxProfit(price, n, k));
    }
}
 
// This code is contributed by Anshul Aggarwal.


Python3
# Python program to maximize the profit
# by doing at most k transactions
# given stock prices for n days
 
# Function to find out maximum profit by
# buying & selling a share atmost k times
# given stock price of n days
def maxProfit(prices, n, k):
     
    # Bottom-up DP approach
    profit = [[0 for i in range(k + 1)]
                 for j in range(n)]
     
    # Profit is zero for the first
    # day and for zero transactions
    for i in range(1, n):
         
        for j in range(1, k + 1):
            max_so_far = 0
             
            for l in range(i):
                max_so_far = max(max_so_far, prices[i] -
                            prices[l] + profit[l][j - 1])
                             
            profit[i][j] = max(profit[i - 1][j], max_so_far)
     
    return profit[n - 1][k]
 
# Driver code
k = 2
prices = [10, 22, 5, 75, 65, 80]
n = len(prices)
 
print("Maximum profit is:",
       maxProfit(prices, n, k))
 
# This code is contributed by vaibhav29498


C#
// C# program to find out maximum profit by
// buying and selling a share atmost k times
// given stock price of n days
using System;
 
class GFG {
     
    // Function to find out maximum profit by
    // buying & selling/ a share atmost k times
    // given stock price of n days
    static int maxProfit(int[] price, int n, int k)
    {
        // table to store results of subproblems
        // profit[t][i] stores maximum profit using atmost
        // t transactions up to day i (including day i)
        int[, ] profit = new int[k + 1, n + 1];
 
        // For day 0, you can't earn money
        // irrespective of how many times you trade
        for (int i = 0; i <= k; i++)
            profit[i, 0] = 0;
 
        // profit is 0 if we don't do any transaction
        // (i.e. k =0)
        for (int j = 0; j <= n; j++)
            profit[0, j] = 0;
 
        // fill the table in bottom-up fashion
        for (int i = 1; i <= k; i++) {
            for (int j = 1; j < n; j++) {
                int max_so_far = 0;
 
                for (int m = 0; m < j; m++)
                max_so_far = Math.Max(max_so_far, price[j] -
                               price[m] + profit[i - 1, m]);
 
                profit[i, j] = Math.Max(profit[i, j - 1], max_so_far);
            }
        }
 
        return profit[k, n - 1];
    }
 
    // Driver code to test above
    public static void Main()
    {
        int k = 2;
        int[] price = { 10, 22, 5, 75, 65, 80 };
 
        int n = price.Length;
 
        Console.Write("Maximum profit is: " +
                     maxProfit(price, n, k));
    }
}
 
// This code is contributed by Sam007


PHP


Javascript


C++
// C++ program to find out maximum profit by buying
// and/ selling a share atmost k times given stock
// price of n days
#include 
#include 
using namespace std;
 
// Function to find out maximum profit by buying &
// selling/ a share atmost k times given stock price
// of n days
int maxProfit(int price[], int n, int k)
{
    // table to store results of subproblems
    // profit[t][i] stores maximum profit using atmost
    // t transactions up to day i (including day i)
    int profit[k + 1][n + 1];
 
    // For day 0, you can't earn money
    // irrespective of how many times you trade
    for (int i = 0; i <= k; i++)
        profit[i][0] = 0;
 
    // profit is 0 if we don't do any transaction
    // (i.e. k =0)
    for (int j = 0; j <= n; j++)
        profit[0][j] = 0;
 
    // fill the table in bottom-up fashion
    for (int i = 1; i <= k; i++) {
        int prevDiff = INT_MIN;
        for (int j = 1; j < n; j++) {
            prevDiff = max(prevDiff,
                           profit[i - 1][j - 1] - price[j - 1]);
            profit[i][j] = max(profit[i][j - 1],
                               price[j] + prevDiff);
        }
    }
 
    return profit[k][n - 1];
}
 
// Driver Code
int main()
{
    int k = 3;
    int price[] = { 12, 14, 17, 10, 14, 13, 12, 15 };
 
    int n = sizeof(price) / sizeof(price[0]);
 
    cout << "Maximum profit is: "
         << maxProfit(price, n, k);
 
    return 0;
}


Java
// Java program to find out maximum
// profit by buying and selling a
// share atmost k times given stock
// price of n days
import java.io.*;
 
class GFG {
     
    // Function to find out maximum profit by
    // buying & selling/ a share atmost k times
    // given stock price of n days
    static int maxProfit(int price[],
                         int n, int k)
    {
         
        // table to store results of subproblems
        // profit[t][i] stores maximum profit
        // using atmost t transactions up to day
        // i (including day i)
        int profit[][] = new int[k + 1][ n + 1];
 
        // For day 0, you can't earn money
        // irrespective of how many times you trade
        for (int i = 0; i <= k; i++)
            profit[i][0] = 0;
 
        // profit is 0 if we don't do any
        // transaction (i.e. k =0)
        for (int j = 0; j <= n; j++)
            profit[0][j] = 0;
 
        // fill the table in bottom-up fashion
        for (int i = 1; i <= k; i++)
        {
            int prevDiff = Integer.MIN_VALUE;
            for (int j = 1; j < n; j++)
            {
                prevDiff = Math.max(prevDiff,
                           profit[i - 1][j - 1] -
                           price[j - 1]);
                profit[i][j] = Math.max(profit[i][j - 1],
                               price[j] + prevDiff);
            }
        }
 
        return profit[k][n - 1];
    }
 
// Driver code
public static void main (String[] args)
    {
        int k = 3;
        int price[] = {12, 14, 17, 10, 14, 13, 12, 15};
 
        int n = price.length;
 
        System.out.println("Maximum profit is: " +
                            maxProfit(price, n, k));
    }
}
 
// This code is contributed by Sam007


Python3
# Python3 program to find out maximum
# profit by buying and/ selling a share
# at most k times given the stock price
# of n days
 
# Function to find out maximum profit
# by buying & selling/ a share atmost
# k times given stock price of n days
def maxProfit(price, n, k):
 
    # Table to store results of subproblems
    # profit[t][i] stores maximum profit
    # using atmost t transactions up to
    # day i (including day i)
    profit = [[0 for i in range(n + 1)]
                 for j in range(k + 1)]
 
    # Fill the table in bottom-up fashion
    for i in range(1, k + 1):
        prevDiff = float('-inf')
         
        for j in range(1, n):
            prevDiff = max(prevDiff,
                           profit[i - 1][j - 1] -
                           price[j - 1])
            profit[i][j] = max(profit[i][j - 1],
                               price[j] + prevDiff)
 
    return profit[k][n - 1]
 
# Driver Code
if __name__ == "__main__":
 
    k = 3
    price = [12, 14, 17, 10, 14, 13, 12, 15]
    n = len(price)
 
    print("Maximum profit is:",
           maxProfit(price, n, k))
 
# This code is contributed
# by Rituraj Jain


C#
// C# program to find out maximum profit by buying
// and selling a share atmost k times given stock
// price of n days
using System;
 
class GFG {
     
    // Function to find out maximum profit by
    // buying & selling/ a share atmost k times
    // given stock price of n days
    static int maxProfit(int[] price, int n, int k)
    {
        // table to store results of subproblems
        // profit[t][i] stores maximum profit using atmost
        // t transactions up to day i (including day i)
        int[, ] profit = new int[k + 1, n + 1];
 
        // For day 0, you can't earn money
        // irrespective of how many times you trade
        for (int i = 0; i <= k; i++)
            profit[i, 0] = 0;
 
        // profit is 0 if we don't do any transaction
        // (i.e. k =0)
        for (int j = 0; j <= n; j++)
            profit[0, j] = 0;
 
        // fill the table in bottom-up fashion
        for (int i = 1; i <= k; i++) {
            int prevDiff = int.MinValue;
            for (int j = 1; j < n; j++) {
            prevDiff = Math.Max(prevDiff,
                            profit[i - 1, j - 1] - price[j - 1]);
            profit[i, j] = Math.Max(profit[i, j - 1],
                                price[j] + prevDiff);
            }
        }
 
        return profit[k, n - 1];
    }
 
    // Driver code to test above
    public static void Main()
    {
        int k = 3;
        int[] price = {12, 14, 17, 10, 14, 13, 12, 15};
 
        int n = price.Length;
 
        Console.Write("Maximum profit is: " +
                     maxProfit(price, n, k));
    }
}
 
// This code is contributed by Sam007


PHP


Javascript


输出 :

Maximum profit is: 87

优化方案:
上述解决方案的时间复杂度为 O(kn 2 )。如果我们能够计算出在固定时间内在第 i 天出售股票所获得的最大利润,则可以减少它。
利润[t][i] = max(利润[t][i-1], max(价格[i] – 价格[j] + 利润[t-1][j]))
对于 [0, i-1] 范围内的所有 j
如果我们仔细观察,
max(价格[i] – 价格[j] + 利润[t-1][j])
对于 [0, i-1] 范围内的所有 j
可以改写为,
= 价格[i] + 最大值(利润[t-1][j] – 价格[j])
对于 [0, i-1] 范围内的所有 j
= 价格[i] + max(prevDiff, 利润[t-1][i-1] – 价格[i-1])
其中 prevDiff 是最大值(利润 [t-1][j] – 价格 [j])
对于 [0, i-2] 范围内的所有 j
因此,如果我们已经为 [0, i-2] 范围内的所有 j 计算了 max(profit[t-1][j] – price[j]),我们可以在恒定时间内计算 j = i – 1 .换句话说,我们不必再在 [0, i-1] 范围内回过头来找出最佳购买日期。我们可以使用以下修正关系在恒定时间内确定。
利润[t][i] = max(利润[t][i-1], 价格[i] + max(prevDiff, 利润[t-1][i-1] – 价格[i-1])
对于 [0, i-2] 范围内的所有 j,prevDiff 是 max(profit[t-1][j] – price[j])
下面是它的优化实现——

C++

// C++ program to find out maximum profit by buying
// and/ selling a share atmost k times given stock
// price of n days
#include 
#include 
using namespace std;
 
// Function to find out maximum profit by buying &
// selling/ a share atmost k times given stock price
// of n days
int maxProfit(int price[], int n, int k)
{
    // table to store results of subproblems
    // profit[t][i] stores maximum profit using atmost
    // t transactions up to day i (including day i)
    int profit[k + 1][n + 1];
 
    // For day 0, you can't earn money
    // irrespective of how many times you trade
    for (int i = 0; i <= k; i++)
        profit[i][0] = 0;
 
    // profit is 0 if we don't do any transaction
    // (i.e. k =0)
    for (int j = 0; j <= n; j++)
        profit[0][j] = 0;
 
    // fill the table in bottom-up fashion
    for (int i = 1; i <= k; i++) {
        int prevDiff = INT_MIN;
        for (int j = 1; j < n; j++) {
            prevDiff = max(prevDiff,
                           profit[i - 1][j - 1] - price[j - 1]);
            profit[i][j] = max(profit[i][j - 1],
                               price[j] + prevDiff);
        }
    }
 
    return profit[k][n - 1];
}
 
// Driver Code
int main()
{
    int k = 3;
    int price[] = { 12, 14, 17, 10, 14, 13, 12, 15 };
 
    int n = sizeof(price) / sizeof(price[0]);
 
    cout << "Maximum profit is: "
         << maxProfit(price, n, k);
 
    return 0;
}

Java

// Java program to find out maximum
// profit by buying and selling a
// share atmost k times given stock
// price of n days
import java.io.*;
 
class GFG {
     
    // Function to find out maximum profit by
    // buying & selling/ a share atmost k times
    // given stock price of n days
    static int maxProfit(int price[],
                         int n, int k)
    {
         
        // table to store results of subproblems
        // profit[t][i] stores maximum profit
        // using atmost t transactions up to day
        // i (including day i)
        int profit[][] = new int[k + 1][ n + 1];
 
        // For day 0, you can't earn money
        // irrespective of how many times you trade
        for (int i = 0; i <= k; i++)
            profit[i][0] = 0;
 
        // profit is 0 if we don't do any
        // transaction (i.e. k =0)
        for (int j = 0; j <= n; j++)
            profit[0][j] = 0;
 
        // fill the table in bottom-up fashion
        for (int i = 1; i <= k; i++)
        {
            int prevDiff = Integer.MIN_VALUE;
            for (int j = 1; j < n; j++)
            {
                prevDiff = Math.max(prevDiff,
                           profit[i - 1][j - 1] -
                           price[j - 1]);
                profit[i][j] = Math.max(profit[i][j - 1],
                               price[j] + prevDiff);
            }
        }
 
        return profit[k][n - 1];
    }
 
// Driver code
public static void main (String[] args)
    {
        int k = 3;
        int price[] = {12, 14, 17, 10, 14, 13, 12, 15};
 
        int n = price.length;
 
        System.out.println("Maximum profit is: " +
                            maxProfit(price, n, k));
    }
}
 
// This code is contributed by Sam007

蟒蛇3

# Python3 program to find out maximum
# profit by buying and/ selling a share
# at most k times given the stock price
# of n days
 
# Function to find out maximum profit
# by buying & selling/ a share atmost
# k times given stock price of n days
def maxProfit(price, n, k):
 
    # Table to store results of subproblems
    # profit[t][i] stores maximum profit
    # using atmost t transactions up to
    # day i (including day i)
    profit = [[0 for i in range(n + 1)]
                 for j in range(k + 1)]
 
    # Fill the table in bottom-up fashion
    for i in range(1, k + 1):
        prevDiff = float('-inf')
         
        for j in range(1, n):
            prevDiff = max(prevDiff,
                           profit[i - 1][j - 1] -
                           price[j - 1])
            profit[i][j] = max(profit[i][j - 1],
                               price[j] + prevDiff)
 
    return profit[k][n - 1]
 
# Driver Code
if __name__ == "__main__":
 
    k = 3
    price = [12, 14, 17, 10, 14, 13, 12, 15]
    n = len(price)
 
    print("Maximum profit is:",
           maxProfit(price, n, k))
 
# This code is contributed
# by Rituraj Jain

C#

// C# program to find out maximum profit by buying
// and selling a share atmost k times given stock
// price of n days
using System;
 
class GFG {
     
    // Function to find out maximum profit by
    // buying & selling/ a share atmost k times
    // given stock price of n days
    static int maxProfit(int[] price, int n, int k)
    {
        // table to store results of subproblems
        // profit[t][i] stores maximum profit using atmost
        // t transactions up to day i (including day i)
        int[, ] profit = new int[k + 1, n + 1];
 
        // For day 0, you can't earn money
        // irrespective of how many times you trade
        for (int i = 0; i <= k; i++)
            profit[i, 0] = 0;
 
        // profit is 0 if we don't do any transaction
        // (i.e. k =0)
        for (int j = 0; j <= n; j++)
            profit[0, j] = 0;
 
        // fill the table in bottom-up fashion
        for (int i = 1; i <= k; i++) {
            int prevDiff = int.MinValue;
            for (int j = 1; j < n; j++) {
            prevDiff = Math.Max(prevDiff,
                            profit[i - 1, j - 1] - price[j - 1]);
            profit[i, j] = Math.Max(profit[i, j - 1],
                                price[j] + prevDiff);
            }
        }
 
        return profit[k, n - 1];
    }
 
    // Driver code to test above
    public static void Main()
    {
        int k = 3;
        int[] price = {12, 14, 17, 10, 14, 13, 12, 15};
 
        int n = price.Length;
 
        Console.Write("Maximum profit is: " +
                     maxProfit(price, n, k));
    }
}
 
// This code is contributed by Sam007

PHP


Javascript


输出 :

Maximum profit is: 12

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程