📜  买卖股票的最佳时机

📅  最后修改于: 2022-05-13 01:56:04.247000             🧑  作者: Mango

买卖股票的最佳时机

类型一:最多允许一次交易

给定一个长度为N的数组price[] ,表示不同日期的股票价格,任务是使用最多允许一次交易的交易,找到在不同日期买卖股票的最大可能利润。

注意:股票必须在出售前购买。

例子:

方法:可以基于找到两个数组元素之间的最大差异的想法来解决给定的问题,其中较小的数字出现在较大的数字之前。因此,这个问题可以简化为为每对索引ij找到max⁡(prices[j]−prices[i]) ,使得j>i

下面是上述方法的实现:

C++
// C++ program for the above approach
 
#include 
#include 
using namespace std;
 
// Function to find maximum profit possible
// by buying and selling at most one stack
int findMaximumProfit(vector& prices, int i, int k,
                      bool buy, vector >& v)
{
    // If no stock can be chosen
    if (i >= prices.size() || k <= 0)
        return 0;
 
    if (v[i][buy] != -1)
        return v[i][buy];
 
    // If a stock is already bought
    if (buy) {
        return v[i][buy]
               = max(-prices[i]
                         + findMaximumProfit(prices, i + 1,
                                             k, !buy, v),
                     findMaximumProfit(prices, i + 1, k,
                                       buy, v));
    }
 
    // Otherwise
    else {
        // Buy now
        return v[i][buy]
               = max(prices[i]
                         + findMaximumProfit(
                             prices, i + 1, k - 1, !buy, v),
                     findMaximumProfit(prices, i + 1, k,
                                       buy, v));
    }
}
 
// Function to find the maximum
// profit in the buy and sell stock
int maxProfit(vector& prices)
{
 
    int n = prices.size();
    vector > v(n, vector(2, -1));
 
    // buy = 1 because atmost one
    // transaction is allowed
    return findMaximumProfit(prices, 0, 1, 1, v);
}
 
// Driver Code
int main()
{
    // Given prices
    vector prices = { 7, 1, 5, 3, 6, 4 };
 
    // Function Call to find the
    // maximum profit possible by
    // buying and selling a single stock
    int ans = maxProfit(prices);
 
    // Print answer
    cout << ans << endl;
 
    return 0;
}


Java
// Java code for the above approach
import java.util.*;
 
class GFG{
 
// Function to find maximum profit possible
// by buying and selling at most one stack
static int findMaximumProfit(int[] prices, int i, int k,
                             int buy, int[][] v)
{
     
    // If no stock can be chosen
    if (i >= prices.length || k <= 0)
        return 0;
 
    if (v[i][buy] != -1)
        return v[i][buy];
 
    // If a stock is already bought
    // Buy now
    int nbuy;
    if (buy == 1)
        nbuy = 0;
    else
        nbuy = 1;
    if (buy == 1)
    {
        return v[i][buy] = Math.max(-prices[i] +
         findMaximumProfit(prices, i + 1, k, nbuy, v),
         findMaximumProfit(prices, i + 1, k, (int)(buy), v));
    }
 
    // Otherwise
    else
    {
         
        // Buy now
        if (buy == 1)
            nbuy = 0;
        else
            nbuy = 1;
        return v[i][buy] = Math.max(prices[i] +
         findMaximumProfit(prices, i + 1, k - 1, nbuy, v),
         findMaximumProfit(prices, i + 1, k, buy, v));
    }
}
 
// Function to find the maximum
// profit in the buy and sell stock
static int maxProfit(int[] prices)
{
    int n = prices.length;
    int[][] v = new int[n][2];
 
    for(int i = 0; i < v.length; i++)
    {
        v[i][0] = -1;
        v[i][1] = -1;
    }
 
    // buy = 1 because atmost one
    // transaction is allowed
    return findMaximumProfit(prices, 0, 1, 1, v);
}
 
// Driver Code
public static void main(String[] args)
{
     
    // Given prices
    int[] prices = { 7, 1, 5, 3, 6, 4 };
 
    // Function Call to find the
    // maximum profit possible by
    // buying and selling a single stock
    int ans = maxProfit(prices);
 
    // Print answer
    System.out.println(ans);
}
 
// This code is contributed by Potta Lokesh


Python3
# Python 3 program for the above approach
 
 
# Function to find maximum profit possible
# by buying and selling at most one stack
def findMaximumProfit(prices, i,  k,
                      buy, v):
 
    # If no stock can be chosen
    if (i >= len(prices) or k <= 0):
        return 0
 
    if (v[i][buy] != -1):
        return v[i][buy]
 
    # If a stock is already bought
    if (buy):
        v[i][buy] = max(-prices[i]
                        + findMaximumProfit(prices, i + 1,
                                            k, not buy, v),
                        findMaximumProfit(prices, i + 1, k,
                                          buy, v))
        return v[i][buy]
 
    # Otherwise
    else:
        # Buy now
        v[i][buy] = max(prices[i]
                        + findMaximumProfit(
            prices, i + 1, k - 1, not buy, v),
            findMaximumProfit(prices, i + 1, k,
                              buy, v))
        return v[i][buy]
 
 
# Function to find the maximum
# profit in the buy and sell stock
def maxProfit(prices):
 
    n = len(prices)
    v = [[-1 for x in range(2)]for y in range(n)]
 
    # buy = 1 because atmost one
    # transaction is allowed
    return findMaximumProfit(prices, 0, 1, 1, v)
 
 
# Driver Code
if __name__ == "__main__":
 
    # Given prices
    prices = [7, 1, 5, 3, 6, 4]
 
    # Function Call to find the
    # maximum profit possible by
    # buying and selling a single stock
    ans = maxProfit(prices)
 
    # Print answer
    print(ans)


C#
// C# program for above approach
using System;
 
class GFG
{
 
// Function to find maximum profit possible
// by buying and selling at most one stack
static int findMaximumProfit(int[] prices, int i, int k,
                             int buy, int[,] v)
{
     
    // If no stock can be chosen
    if (i >= prices.Length || k <= 0)
        return 0;
 
    if (v[i, buy] != -1)
        return v[i, buy];
 
    // If a stock is already bought
    // Buy now
    int nbuy;
    if (buy == 1)
        nbuy = 0;
    else
        nbuy = 1;
    if (buy == 1)
    {
        return v[i, buy] = Math.Max(-prices[i] +
         findMaximumProfit(prices, i + 1, k, nbuy, v),
         findMaximumProfit(prices, i + 1, k, (int)(buy), v));
    }
 
    // Otherwise
    else
    {
         
        // Buy now
        if (buy == 1)
            nbuy = 0;
        else
            nbuy = 1;
        return v[i, buy] = Math.Max(prices[i] +
         findMaximumProfit(prices, i + 1, k - 1, nbuy, v),
         findMaximumProfit(prices, i + 1, k, buy, v));
    }
}
 
// Function to find the maximum
// profit in the buy and sell stock
static int maxProfit(int[] prices)
{
    int n = prices.Length;
    int[,] v = new int[n, 2];
 
    for(int i = 0; i < n; i++)
    {
        v[i, 0] = -1;
        v[i, 1] = -1;
    }
 
    // buy = 1 because atmost one
    // transaction is allowed
    return findMaximumProfit(prices, 0, 1, 1, v);
}
 
// Driver Code
public static void Main()
{
   
    // Given prices
    int[] prices = { 7, 1, 5, 3, 6, 4 };
 
    // Function Call to find the
    // maximum profit possible by
    // buying and selling a single stock
    int ans = maxProfit(prices);
 
    // Print answer
    Console.Write(ans);
         
}
}
 
// This code is contributed by Samim Hossain Mondal.


Javascript


C++
// C++ program for the above approach
#include 
using namespace std;
 
// Function to calculate maximum
// profit possible by buying or
// selling stocks any number of times
int find(int ind, vector& v, bool buy,
         vector >& memo)
{
 
    // No prices left
    if (ind >= v.size())
        return 0;
 
    // Already found
    if (memo[ind][buy] != -1)
        return memo[ind][buy];
 
    // Already bought, now sell
    if (buy) {
        return memo[ind][buy]
               = max(-v[ind] + find(ind + 1, v, !buy, memo),
                     find(ind + 1, v, buy, memo));
    }
 
    // Otherwise, buy the stock
    else {
        return memo[ind][buy]
               = max(v[ind] + find(ind + 1, v, !buy, memo),
                     find(ind + 1, v, buy, memo));
    }
}
 
// Function to find the maximum
// profit possible by buying and
// selling stocks any number of times
int maxProfit(vector& prices)
{
    int n = prices.size();
    if (n < 2)
        return 0;
 
    vector > v(n + 1, vector(2, -1));
    return find(0, prices, 1, v);
}
 
// Driver Code
int main()
{
 
    // Given prices
    vector prices = { 7, 1, 5, 3, 6, 4 };
 
    // Function Call to calculate
      // maximum profit possible
    int ans = maxProfit(prices);
 
    // Print the total profit
    cout << ans << endl;
    return 0;
}


C++
// C++ program for the above approach
 
#include 
#include 
using namespace std;
 
// Function to find the maximum
// profit in the buy and sell stock
int find(vector& prices, int ind, bool buy, int c,
         vector > >& memo)
{
    // If buy =1 means buy now
    // else sell
    if (ind >= prices.size() || c >= 2)
        return 0;
    if (memo[ind][buy] != -1)
        return memo[ind][buy];
 
    // Already bought, sell now
    if (buy) {
        return memo[ind][buy]
               = max(-prices[ind]
                         + find(prices, ind + 1, !buy, c,
                                memo),
                     find(prices, ind + 1, buy, c, memo));
    }
 
    // Can buy stocks
    else {
        return memo[ind][buy]
               = max(prices[ind]
                         + find(prices, ind + 1, !buy,
                                c + 1, memo),
                     find(prices, ind + 1, buy, c, memo));
    }
}
 
// Function to find the maximum
// profit in the buy and sell stock
int maxProfit(vector& prices)
{
    // Here maximum two transaction are allowed
 
    // Use 3-D vector because here
    // three states are there: i,k,buy/sell
    vector > > memo(
        prices.size(),
        vector >(2, vector(2, -1)));
 
    // Answer
    return find(prices, 0, 1, 0, memo);
}
 
// Driver Code
int main()
{
 
    // Given prices
    vector prices = { 3, 3, 5, 0, 0, 3, 1, 4 };
 
    // Function Call
    int ans = maxProfit(prices);
 
    // Answer
    cout << ans << endl;
    return 0;
}


C++
// C++ program for the above approach
 
#include 
#include 
using namespace std;
 
// Function to find the maximum
// profit with atmost K transactions
int find(vector& prices, int ind, bool buy, int c,
         int k, vector > >& memo)
{
 
    // If there are no more transaction
    // allowed, return the profit as 0
    if (ind >= prices.size() || c >= k)
        return 0;
 
    // Memoize
    else if (memo[ind][buy] != -1)
        return memo[ind][buy];
 
    // Already bought, now sell
    if (buy) {
        return memo[ind][buy] = max(
                   -prices[ind]
                       + find(prices, ind + 1, !buy, c, k,
                              memo),
                   find(prices, ind + 1, buy, c, k, memo));
    }
 
    // Stocks can be bought
    else {
        return memo[ind][buy] = max(
                   prices[ind]
                       + find(prices, ind + 1, !buy, c + 1,
                              k, memo),
                   find(prices, ind + 1, buy, c, k, memo));
    }
}
 
// Function to find the maximum profit
// in the buy and sell stock
int maxProfit(int k, vector& prices)
{
    // If transactions are greater
    // than number of prices
    if (2 * k > prices.size()) {
        int res = 0;
        for (int i = 1; i < prices.size(); i++) {
            res += max(0, prices[i] - prices[i - 1]);
        }
        return res;
    }
 
    // Maximum k transaction
    vector > > memo(
        prices.size() + 1,
        vector >(2, vector(k + 1, -1)));
    return find(prices, 0, 1, 0, k, memo);
}
 
// Driver Code
int main()
{
 
    // Given prices
    vector prices = { 2, 4, 1 };
 
    // Given K
    int k = 2;
 
    // Function Call
    int ans = maxProfit(k, prices);
 
    // Print answer
    cout << ans << endl;
    return 0;
}


输出
5

时间复杂度: O(N),其中 N 是给定数组的长度。
辅助空间: O(N)

类型二:允许无限交易

给定一个长度为N的数组price[] ,表示不同日期的股票价格,任务是使用允许任意数量的交易的交易,找到在不同日期买卖股票的最大可能利润。

例子:

方法:这个想法是保持一个布尔值,表示当前是否正在进行购买。如果是,那么在当前状态下,可以出售股票以实现利润最大化,或者在不出售股票的情况下转移到下一个价格。否则,如果没有交易发生,则可以购买当前股票或移动到下一个价格而不购买

下面是上述方法的实现:

C++

// C++ program for the above approach
#include 
using namespace std;
 
// Function to calculate maximum
// profit possible by buying or
// selling stocks any number of times
int find(int ind, vector& v, bool buy,
         vector >& memo)
{
 
    // No prices left
    if (ind >= v.size())
        return 0;
 
    // Already found
    if (memo[ind][buy] != -1)
        return memo[ind][buy];
 
    // Already bought, now sell
    if (buy) {
        return memo[ind][buy]
               = max(-v[ind] + find(ind + 1, v, !buy, memo),
                     find(ind + 1, v, buy, memo));
    }
 
    // Otherwise, buy the stock
    else {
        return memo[ind][buy]
               = max(v[ind] + find(ind + 1, v, !buy, memo),
                     find(ind + 1, v, buy, memo));
    }
}
 
// Function to find the maximum
// profit possible by buying and
// selling stocks any number of times
int maxProfit(vector& prices)
{
    int n = prices.size();
    if (n < 2)
        return 0;
 
    vector > v(n + 1, vector(2, -1));
    return find(0, prices, 1, v);
}
 
// Driver Code
int main()
{
 
    // Given prices
    vector prices = { 7, 1, 5, 3, 6, 4 };
 
    // Function Call to calculate
      // maximum profit possible
    int ans = maxProfit(prices);
 
    // Print the total profit
    cout << ans << endl;
    return 0;
}
输出
7

时间复杂度: O(N),其中 N 是给定数组的长度。
辅助空间: O(N)

第三类:最多允许两次交易

问题:给定一个长度为N的数组price[] ,它表示不同日期的股票价格。任务是使用最多允许两次交易的交易找到在不同日期买卖股票的最大利润。

注意:股票必须在出售前购买。

方法:按照上述方法可以解决问题。现在,如果交易次数等于 2,那么当前的利润可能是想要的答案。同样,通过将所有可能的答案记忆到 DP 表中来尝试所有可能的答案。

下面是上述方法的实现:

C++

// C++ program for the above approach
 
#include 
#include 
using namespace std;
 
// Function to find the maximum
// profit in the buy and sell stock
int find(vector& prices, int ind, bool buy, int c,
         vector > >& memo)
{
    // If buy =1 means buy now
    // else sell
    if (ind >= prices.size() || c >= 2)
        return 0;
    if (memo[ind][buy] != -1)
        return memo[ind][buy];
 
    // Already bought, sell now
    if (buy) {
        return memo[ind][buy]
               = max(-prices[ind]
                         + find(prices, ind + 1, !buy, c,
                                memo),
                     find(prices, ind + 1, buy, c, memo));
    }
 
    // Can buy stocks
    else {
        return memo[ind][buy]
               = max(prices[ind]
                         + find(prices, ind + 1, !buy,
                                c + 1, memo),
                     find(prices, ind + 1, buy, c, memo));
    }
}
 
// Function to find the maximum
// profit in the buy and sell stock
int maxProfit(vector& prices)
{
    // Here maximum two transaction are allowed
 
    // Use 3-D vector because here
    // three states are there: i,k,buy/sell
    vector > > memo(
        prices.size(),
        vector >(2, vector(2, -1)));
 
    // Answer
    return find(prices, 0, 1, 0, memo);
}
 
// Driver Code
int main()
{
 
    // Given prices
    vector prices = { 3, 3, 5, 0, 0, 3, 1, 4 };
 
    // Function Call
    int ans = maxProfit(prices);
 
    // Answer
    cout << ans << endl;
    return 0;
}
输出
6

时间复杂度: O(N),其中 N 是给定数组的长度。
辅助空间: O(N)

第四类:最多允许 K 笔交易

问题:给定一个长度为N的数组price[] ,它表示不同日期的股票价格。任务是使用最多允许K次交易的交易,找出在不同日期买卖股票的最大可能利润。

注意:股票必须在出售前购买。

例子:

方法:这个想法是保持已完成的事务计数,并将事务计数与K进行比较如果小于K ,则买卖股票。否则,当前利润可以是最大利润。

下面是上述方法的实现:

C++

// C++ program for the above approach
 
#include 
#include 
using namespace std;
 
// Function to find the maximum
// profit with atmost K transactions
int find(vector& prices, int ind, bool buy, int c,
         int k, vector > >& memo)
{
 
    // If there are no more transaction
    // allowed, return the profit as 0
    if (ind >= prices.size() || c >= k)
        return 0;
 
    // Memoize
    else if (memo[ind][buy] != -1)
        return memo[ind][buy];
 
    // Already bought, now sell
    if (buy) {
        return memo[ind][buy] = max(
                   -prices[ind]
                       + find(prices, ind + 1, !buy, c, k,
                              memo),
                   find(prices, ind + 1, buy, c, k, memo));
    }
 
    // Stocks can be bought
    else {
        return memo[ind][buy] = max(
                   prices[ind]
                       + find(prices, ind + 1, !buy, c + 1,
                              k, memo),
                   find(prices, ind + 1, buy, c, k, memo));
    }
}
 
// Function to find the maximum profit
// in the buy and sell stock
int maxProfit(int k, vector& prices)
{
    // If transactions are greater
    // than number of prices
    if (2 * k > prices.size()) {
        int res = 0;
        for (int i = 1; i < prices.size(); i++) {
            res += max(0, prices[i] - prices[i - 1]);
        }
        return res;
    }
 
    // Maximum k transaction
    vector > > memo(
        prices.size() + 1,
        vector >(2, vector(k + 1, -1)));
    return find(prices, 0, 1, 0, k, memo);
}
 
// Driver Code
int main()
{
 
    // Given prices
    vector prices = { 2, 4, 1 };
 
    // Given K
    int k = 2;
 
    // Function Call
    int ans = maxProfit(k, prices);
 
    // Print answer
    cout << ans << endl;
    return 0;
}
输出
2

时间复杂度: O(N*K),其中 N 是给定数组的长度,K 是允许的事务数。
辅助空间: O(N*K)