Reference: LeetCode
Difficulty: Easy
My Post: Java Solution with Comments and Explanation (BF, Divide and Conquer, One-Pass)
Problem
Say you have an array for which the ith element is the price of a given stock on day
i.
If you were only permitted to complete at most one transaction (i.e., buy one and sell one share of the stock), design an algorithm to find the maximum profit.
Constraint: Note that you cannot sell a stock before you buy one.
Example:
1 | Input: [7,1,5,3,6,4] |
1 | Input: [7,6,4,3,1] |
Analysis
Brute-Force
For each day i, compare its prices with the following price of each day j, and update the maximum profit.
Note:
jshould starts from0.maxProfitshould be initialized with $0$.
1 | public int maxProfit(int[] prices) { |
Time: $O(N^2)$
Space: $O(1)$
Divide and Conquer
We divide the problem into two subproblems left and right. Then we calculate:
- The best buy time
B1and the best sell timeS1fromleft. - The best buy time
B2and the best sell timeS2fromright. - The time
M1of minimum price and the timeX1of maximum price inleft. - The time
M2of minimum price and the timeX2of maximum price inright.
In the combine step, we have three cases to consider:
- Case 1: In
left, we buy atB1and sell atS1. - Case 2: In
right, we buy atB2and sell atS2. - Case 3: In
leftandright, we buy atM1and sell atX2.- We cannot use
B1andS2becauseB1may not be the time of minimum price andS2may not be the time of maximum price. Check out the illustration below.
- We cannot use
- Beside, we need to update the time of minimum price and maximum price.
Here is an illustration of the text above. Notice the left is P1 and right is P2.
![]()
The following solution uses a helper class BuySell to encapsulate variables passed across recursive levels.
1 | private class BuySell { |
Here is the main part of the solution. Notice that it is a good approach to separate the combining code from the recursive function. It makes code more readable.
1 | public int maxProfit(int[] prices) { |
Time: $O(N)$ since $T(N) = 2T(N) + O(1)$
Space: $O(\log{N})$ because of the call stack.
One-Pass
Notice that the maximum profit that can be made by selling on a specific day is determined by the minimum of the stock prices over the previous days. Thus, we can loop over each price in prices, and keep updating the minimum price and at the same update the maximum profit.
Note: The ordering of updating maxProfit and minPrice does not matter.
1 | public int maxProfit(int[] prices) { |
Time: $O(N)$
Space: $O(1)$