买卖股票的最佳时机
类型一:最多允许一次交易
给定一个长度为N的数组price[] ,表示不同日期的股票价格,任务是使用最多允许一次交易的交易,找到在不同日期买卖股票的最大可能利润。
注意:股票必须在出售前购买。
例子:
Input: prices[] = {7, 1, 5, 3, 6, 4]
Output: 5
Explanation:
The lowest price of the stock is on the 2nd day, i.e. price = 1. Starting from the 2nd day, the highest price of the stock is witnessed on the 5th day, i.e. price = 6.
Therefore, maximum possible profit = 6 – 1 = 5.
Input: prices[] = {7, 6, 4, 3, 1}
Output: 0
Explanation: Since the array is in decreasing order, no possible way exists to solve the problem.
方法:可以基于找到两个数组元素之间的最大差异的想法来解决给定的问题,其中较小的数字出现在较大的数字之前。因此,这个问题可以简化为为每对索引i和j找到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[] ,表示不同日期的股票价格,任务是使用允许任意数量的交易的交易,找到在不同日期买卖股票的最大可能利润。
例子:
Input: prices[] = {7, 1, 5, 3, 6, 4}
Output: 7
Explanation:
Purchase on 2nd day. Price = 1.
Sell on 3rd day. Price = 5.
Therefore, profit = 5 – 1 = 4.
Purchase on 4th day. Price = 3.
Sell on 5th day. Price = 6.
Therefore, profit = 4 + (6 – 3) = 7.
Input: prices = {1, 2, 3, 4, 5}
Output: 4
Explanation:
Purchase on 1st day. Price = 1.
Sell on 5th day. Price = 5.
Therefore, profit = 5 – 1 = 4.
方法:这个想法是保持一个布尔值,表示当前是否正在进行购买。如果是,那么在当前状态下,可以出售股票以实现利润最大化,或者在不出售股票的情况下转移到下一个价格。否则,如果没有交易发生,则可以购买当前股票或移动到下一个价格而不购买。
下面是上述方法的实现:
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[] ,它表示不同日期的股票价格。任务是使用最多允许两次交易的交易找到在不同日期买卖股票的最大利润。
注意:股票必须在出售前购买。
Input: prices[] = {3, 3, 5, 0, 0, 3, 1, 4}
Output: 6
Explanation:
Buy on Day 4 and Sell at Day 6 => Profit = 3 0 = 3
Buy on Day 7 and Sell at Day 8 => Profit = 4 1 = 3
Therefore, Total Profit = 3 + 3 = 6
Input: prices[] = {1, 2, 3, 4, 5}
Output: 4
Explanation:
Buy on Day 1 and sell at Day 6 => Profit = 5 1 = 4
Therefore, Total Profit = 4
方法:按照上述方法可以解决问题。现在,如果交易次数等于 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次交易的交易,找出在不同日期买卖股票的最大可能利润。
注意:股票必须在出售前购买。
例子:
Input: K = 2, prices[] = {2, 4, 1}
Output: 2
Explanation: Buy on day 1 when price is 2 and sell on day 2 when price is 4. Therefore, profit = 4-2 = 2.
Input: K = 2, prices[] = {3, 2, 6, 5, 0, 3}
Output: 7
Explanation:
Buy on day 2 when price is 2 and sell on day 3 when price is 6. Therefore, profit = 6-2 = 4.
Buy on day 5 when price is 0 and sell on day 6 when price is 3. Therefore, profit = 3-0 = 3.
Therefore, the total profit = 4+3 = 7
方法:这个想法是保持已完成的事务计数,并将事务计数与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)