Problem
You are given an array prices
where prices[i]
is the price of a given stock on the ith
day.
You want to maximize your profit by choosing a single day to buy one stock and choosing a different day in the future to sell that stock.
Return the maximum profit you can achieve from this transaction. If you cannot achieve any profit, return 0
.
OR
Given an array of stock prices, where the increasing indexes of the array signify the increase in time. Return a good time to buy and sell such that profit is maximized. You are allowed to transact only once.
OR
Given an array
A[]
, write an algorithm to find Maximum difference between two elements where larger element appears after the smaller element or in other words findA[i]
andA[j]
such thatA[j]-A[i]
is maximum wherej > i
.
Examples
Example 1:
Input:
prices = [7,1,5,3,6,4]
Output:
5
Explanation: Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5.
Note that buying on day 2 and selling on day 1 is not allowed because you must buy before you sell.
Example 2:
Input:
prices = [7,6,4,3,1]
Output:
0
Explanation: In this case, no transactions are done and the max profit = 0.
Solution
Video explanation
Here is the video explaining below few methods in detail. Please check it out:
Method 1: Brute Force
This problem can be easily solved using two nested loops. Take each element at a time and compare it with all the other elements and keep the track of the maximum difference elements where larger element appears after the smaller element.
Code
Java
class Solution {
public int maxProfit(int[] prices) {
int ans = 0; // Initialise maximum profit
// Loop through all buy-sell pairs
for (int i = 0; i < prices.length; i++) {
for (int j = i + 1; j < prices.length; j++) {
ans = Math.max(ans, prices[j] - prices[i]); // Update maximum profit
}
}
return ans;
}
}
Python
class Solution:
def maxProfit(self, prices: List[int]) -> int:
ans: int = 0 # Initialise maximum profit
# Loop through all buy-sell pairs
for i in range(len(prices)):
for j in range(i + 1, len(prices)):
ans = max(ans, prices[j] - prices[i]) # Update maximum profit
return ans
Complexity
- ⏰ Time complexity:
O(n^2)
, because we use two nested loops to check every pair of buying and selling days. - 🧺 Space complexity:
O(1)
as no additional data structures are used.
Method 2 - Greedy
The optimal solution leverages the idea of keeping track of the minimum price encountered so far and calculating the maximum profit along the way. This avoids the need to compare every pair of days explicitly, making the algorithm much more efficient.
Approach
- Initialise Variables:
min_price
to store the minimum stock price encountered so far (initialised to infinity).ans
to store the maximum profit (initialised to0
).
- Iterate Through Prices:
- At each day:
- Check and update
min_price
if the currentprices[i]
is lower than the currentmin_price
. - Calculate the profit for selling on the current day:
profit = prices[i] - min_price
. - Update
ans
if the calculated profit is greater than the currentans
.
- Check and update
- At each day:
- Return the Result:
- After iterating through all days, return the value of
ans
.
- After iterating through all days, return the value of
Code
Java
class Solution {
public int maxProfit(int[] prices) {
int minPrice = Integer.MAX_VALUE; // Start with the largest possible value
int ans = 0; // Initialise maximum profit
for (int p : prices) {
if (p < minPrice) {
minPrice = p; // Update the minimum price
} else if (p - minPrice > ans) {
ans = p - minPrice; // Update the maximum profit
}
}
return ans;
}
}
Python
class Solution:
def maxProfit(self, prices: List[int]) -> int:
min_price: int = float('inf') # Start with the largest possible value
ans: int = 0 # Initialise maximum profit
for p in prices:
if p < min_price:
min_price = p # Update the minimum price
elif p - min_price > ans:
ans = p - min_price # Update the maximum profit
return ans
Method 3 - Divide and Conquer
We need to find the two elements
A[i]
andA[j]
so thatA[j] – A[i]
is maximum andj > i
Divide the input array into 2 parts, left Half and right half.
We have divided the problem in 2 parts. Now we can conclude that for answer-
- Both indexes i and j are in the left half of the array.
- Both indexes i and j are in the right half of the array.
- Index i is in left half and index j is in right half of the array.
Solve the above 3 sub problems recursively and final answer will the maximum of these 3 sub problems.
This solution is very much similar to Merge sort.
Complexity
Time complexity is O(nlogn).
Code
Java
public int maxProfit(int[] prices) {
return maxProfit(prices, 0, prices.length - 1);
}
private int maxProfit(int[] prices, int start, int end) {
if (start >= end) {
return -1;
}
int mid = start + (end - start) / 2;
int leftDiff = maxProfit(prices, start, mid);
int rightDiff = maxProfit(prices, mid + 1, end);
int minLeft = getMin(prices, start, mid);
int maxRight = getMax(prices, mid, end);
int centerDiff = maxRight - minLeft;
return Math.max(centerDiff, Math.max(leftDiff, rightDiff));
}
public int getMin(int[] nums, int i, int j) {
int min = nums[i];
for (int k = i + 1; k<= j; k++) {
if (nums[k]<min)
min = nums[k];
}
return min;
}
public int getMax(int[] nums, int i, int j) {
int max = nums[i];
for (int k = i + 1; k<= j; k++) {
if (nums[k] > max)
max = nums[k];
}
return max;
}
Method 4 - Kadane - Tracking Diff with Min Element so Far
In this method, instead of taking difference of the picked element with every other element, we take the difference with the minimum element found so far. So we need to keep track of 2 things:
- Maximum difference found so far (max_diff).
- Minimum number visited so far (min_element)
Code
Java
public int maxProfit(int prices[]) {
int maxProfit = Integer.MIN_VALUE;
int minElement = prices[0];
int i;
for (i = 1; i<prices.length; i++) {
if (prices[i] - minElement > max_diff)
maxProfit = prices[i] - minElement;
if (prices[i]<minElement)
minElement = prices[i];
}
return maxProfit;
}
Removing if condition:
public int maxProfit(int[] prices) {
if (prices == null || prices.length<= 1) {
return 0;
}
int min = prices[0]; // min so far
int ans = 0;
for (int i = 1; i<prices.length; i++) {
ans = Math.max(result, prices[i] - min);
min = Math.min(min, prices[i]);
}
return ans;
}
Complexity
Time Complexity: O(n), Auxiliary Space: O(1)
Method 5 - Kadane - Tracking Diff with Max Element so Far
Previous solution was on min_so_far
, now we have max_so_far
.
- Traverse the array from right to left.
- Maintain 2 variables – maxDifference (this will be our final answer), and max_so_far(maximum element we encounter while traversing the array)
- During iteration, every element has 2 choices
- Either current element is the maximum element among elements which are iterated, if yes then max_so_far = current element.
- OR current element is less than the max_so_far. If yes then update the maxDifference = max_so_far – current element.
- Once the iteration is done, return maxDifference.
Complexity
Time complexity: O(n), Space complexity: O(1)
Code
Java
public static int maxDifference(int[] A) {
int size = A.length;
int maxDiff = -1;
int max_so_far = A[size - 1]; //assign the last element
for (int i = size - 2; i > 0; i--) {
if (max_so_far<A[i])
max_so_far = A[i];
else if (max_so_far > A[i])
maxDiff = Math.max(maxDiff, max_so_far - A[i]);
}
return maxDiff;
}
Complexity
Time Complexity: O(n), Auxiliary Space: O(1)
Method 6 - Dynamic Programming - Max Sum Subarray
First find the difference between the adjacent elements of the array and store all differences in an auxiliary array diff[] of size n-1. Now this problems turns into finding the maximum sum subarray of this difference array.
Code
Java
int maxProfit(int prices[],) {
// Create a diff array of size n-1. The array will
// hold the difference of adjacent elements
int diff[] = new int[n - 1];
for (int i = 0; i<n - 1; i++) {
diff[i] = arr[i + 1] - arr[i];
}
// Now find the maximum sum subarray in diff array
int maxDiff = diff[0];
for (int i = 1; i<n - 1; i++) {
if (diff[i - 1] > 0) {
diff[i] += diff[i - 1];
}
if (maxDiff<diff[i]) {
maxDiff = diff[i];
}
}
return maxDiff;
}
Method 7 - 2 Pointer Approach
Code
Java
int maxProfit(int arr[]) {
int l = 0, r = 1; // left buy, right sell
int maxProfit = 0;
while(r < arr.length) {
// is profitable transaction?
if(price[l] < price[r]){
int profit = price[r] - price[l]
maxProfit = Math.max(profit, maxProfit);
}else {
l = r;
}
r++;
}
}
Complexity
Time Complexity: O(n), Auxiliary Space: O(1)