Photo by Nicholas Cappello on Unsplash
Explore LeetCode : Best Time to Buy and Sell Stock
Maximizing Profit in Stock Trading through Dynamic Programming
Introduction
Welcome to our exploration of the "Best Time to Buy and Sell Stock" problem on LeetCode. In this series, we will dive into this widely discussed coding challenge that focuses on maximizing profit in stock trading. By carefully analyzing price fluctuations within a given array, we aim to identify the best moments to buy and sell stocks. Throughout our journey, we will uncover key concepts such as array manipulation, dynamic programming, and effective stock trading strategies. Prepare to enhance your problem-solving skills and conquer this intriguing LeetCode question. Let's embark on this exciting adventure!
Problem Overview
You are given an array
prices
whereprices[i]
is the price of a given stock on thei<sup>th</sup>
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
.
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.
Constraints:
1 <= prices.length <= 10<sup>5</sup>
0 <= prices[i] <= 10<sup>4</sup>
Brute Force Approach
Before we begin the coding section for these questions, it is important to deeply understand and carefully analyze the problem. Through thorough analysis, we can apply a mathematical approach to solving it. Our main goal is to find the maximum profit achievable from selling the stock. To accomplish this, we can utilize the following formula:
Profit = buy price - sell price
Now that we have a good understanding of the formula, we can proceed with implementing it step by step to determine the best profit. Let's go through the following process:
Start by creating a variable that will help us keep track of the maximum profit.
Next, set up a nested loop structure. The outer loop will iterate through the array to track the buy price, while the inner loop will iterate through the subsequent sell prices.
Once we identify the buy price, we can calculate the difference between it and each selling price. This will allow us to determine the highest value among all the differences.
let maximumProfit = 0
for (let i = 0; i < prices.length; i++){
for (let j = i + 1; j < prices.length; j++) {
const tempProfit = prices[j] - prices[i];
maximumProfit = Math.max(tempProfit, maximumProfit)
}
}
return maximumProfit
}
Time and space complexity
The time complexity is determined by the nested loops. The outer loop iterates from 0 to n-1, where n is the length of the prices array. The inner loop iterates from i+1 to n-1. This means that for each element in the array, we compare it with all the subsequent elements. In the worst-case scenario, where the prices array is sorted in descending order, the inner loop will run n-1 times for the first element, n-2 times for the second element, and so on. This results in a total of (n-1) + (n-2) + ... + 1 comparisons, which simplifies to n * (n-1) / 2. Therefore, the time complexity is quadratic, O(n^2).
The space complexity of the code is constant, O(1), as it only uses a single variable, maximumProfit
, to store the maximum profit. The memory usage does not increase with the size of the input array.
In conclusion, the code has a time complexity of O(n^2), indicating it may become inefficient for large input sizes, and space complexity of O(1), indicating it uses a constant amount of memory.
Optimal Approach
With the current brute force approach, we can determine the maximum profit, but it poses a challenge due to its time complexity of O(n^2). As a result, it becomes problematic when dealing with larger input sizes, leading to instances where our code exceeds the time limit on platforms like LeetCode, resulting in unsuccessful submissions. Hence, it becomes imperative for us to optimize and update our code to improve its efficiency and address these limitations.
let maxProfit = 0;
let buyPrice = Number.MAX_VALUE;
for (let i = 0; i < prices.length; i++){
buyPrice = Math.min(buyPrice, prices[i]);
maxProfit = Math.max(maxProfit, prices[i] - buyPrice);
}
return maxProfit;
}
Initialize the
maxProfit
variable to 0. This variable will store the maximum profit that can be achieved.Set the
buyPrice
variable to the maximum value possible (Number.MAX_VALUE
). This variable will keep track of the lowest price at which the stock can be bought.Start a loop that iterates through each price in the
prices
array.Inside the loop, update the
buyPrice
by comparing the current price with the existingbuyPrice
and assigning the smaller value tobuyPrice
. This ensures thatbuyPrice
always stores the lowest price encountered so far.Calculate the potential profit by subtracting the
buyPrice
from the current price (prices[i] - buyPrice
).Update the
maxProfit
by comparing the current profit with the existingmaxProfit
and assigning the larger value tomaxProfit
. This ensures thatmaxProfit
always stores the maximum profit encountered so far.After the loop finishes, the maximum profit is stored in the
maxProfit
variable.Finally, the
maxProfit
value is returned as the result.
Time and space complexity
The Optimal code has a time complexity of O(n), where n is the length of the prices array.
The code iterates through the prices array once, from the first element to the last. It initializes the buyPrice
variable to the maximum possible value initially. Then, for each price in the array, it updates the buyPrice
by choosing the minimum value between the current buyPrice
and the current price in the iteration. This ensures that buyPrice
represents the lowest encountered price so far.
Next, the code calculates the profit by subtracting the buyPrice
from the current price and updates the maxProfit
variable if a higher profit is found. By continually updating maxProfit
during the iteration, the code eventually returns the maximum profit achievable from buying and selling the stocks.
Since the code performs a single pass through the prices array, its time complexity is directly proportional to the length of the array, resulting in a time complexity of O(n). This approach avoids unnecessary nested loops, making it more efficient compared to a brute-force solution.
Test Cases
To improve your understanding of the concept, I suggest trying out some test cases. By experimenting with different inputs and observing the outputs, you can gain a clearer grasp of how the solution functions. This practical approach will help solidify your understanding of the concept.
Test Case 1: Input: [7, 1, 5, 3, 6, 4] Output: 5
Test Case 2: Input: [7, 6, 4, 3, 1] Output: 0
Test Case 3: Input: [2, 4, 1] Output: 2
Test Case 4: Input: [2, 1, 2, 1, 0, 1, 2] Output: 2
Test Case 5: Input: [1, 2, 3, 4, 5] Output: 4
Test Case 6: Input: [7, 6, 5, 4, 3, 2, 1] Output: 0
Test Case 7: Input: [3, 3, 5, 0, 0, 3, 1, 4] Output: 4
Test Case 8: Input: [1] Output: 0
Test Case 9: Input: [1, 2] Output: 1
Test Case 10: Input: [2, 1] Output: 0
Conclusion
Brute force approach: The first code uses a brute force approach to find the maximum profit. It iterates through the prices array using nested loops and compares each element with the subsequent elements. The maximum profit is updated whenever a higher profit is found. However, this approach has a time complexity of O(n^2), making it inefficient for larger input sizes.
Optimal approach: The second code improves upon the first approach by using a more efficient algorithm. It iterates through the prices array only once and keeps track of the minimum buy price encountered so far. It calculates the profit by subtracting the current buy price from each subsequent price and updates the maximum profit if a higher profit is found. This approach has a time complexity of O(n) since it only requires a single pass through the array, resulting in better efficiency compared to the first approach.
In conclusion, the second approach is more efficient in terms of time complexity and provides a better solution for finding the maximum profit from buying and selling stocks. It avoids the "time limit exceeded" issue that may arise with larger inputs, making it a preferable choice over the brute force approach.