Problem
The stock span problem is a financial problem where we have a series of n
daily price quotes for a stock and we need to calculate the span of the stock’s price for all n
days.
The span S[i]
of the stock’s price on a given day i
is defined as the maximum number of consecutive days (starting from today and going backward) for which the stock price was less than or equal to its price on day i
.
Examples
Example 1:
Input: prices = [100, 80, 60, 70, 60, 75, 85]
Output: [1, 1, 1, 2, 1, 4, 6]
Explanation: For each day, the span is calculated as follows:
Price Span Reason
100 1 (No previous day)
80 1 (No previous day <= 80)
60 1 (No previous day <= 60)
70 2 (Day 2 and 3 itself)
60 1 (No previous day <= 60)
75 4 (Days 3, 2, 1, and 0)
85 6 (Days 5, 4, 3, 2, 1, and 0)
Example 2:
Input: prices = [10, 4, 5, 90, 120, 80]
Output: [1, 1, 2, 4, 5, 1]
Explanation: For each day, the span is calculated as follows:
- Day 0: Price = 10, Span = 1
- Day 1: Price = 4, Span = 1
- Day 2: Price = 5, Span = 2
- Day 3: Price = 90, Span = 4
- Day 4: Price = 120, Span = 5
- Day 5: Price = 80, Span = 1
Solution
Method 1 - Brute Force
We can run the 2 nested loops - In outer loop iterate through the prices
array, and in inner loop:
- For each price
prices[i]
, we initiatespan[i]
as1
(the minimum span value, i.e., the current day itself). - We then use an inner loop to check all previous prices
prices[j]
fromi-1
down to0
. - If a previous price
prices[j]
is less than or equal to the current priceprices[i]
, we incrementspan[i]
. - If we encounter a price greater than
prices[i]
, we break out of the inner loop as the span cannot be extended further.
Code
Java
class Solution {
public int[] calculateSpan(int[] prices) {
int n = prices.length;
int[] span = new int[n];
for (int i = 0; i < n; i++) {
span[i] = 1;
for (int j = i - 1; j >= 0; j--) {
if (prices[j] <= prices[i]) {
span[i]++;
} else {
break;
}
}
}
return span;
}
}
Python
class Solution:
def calculateSpan(self, prices: List[int]) -> List[int]:
n = len(prices)
span = [0] * n
for i in range(n):
span[i] = 1
for j in range(i - 1, -1, -1):
if prices[j] <= prices[i]:
span[i] += 1
else:
break
return span
Complexity
- ⏰ Time complexity:
O(n^2)
due to the nested loops. - 🧺 Space complexity:
O(n)
for the output array
Method 2 - Using Monotonic decreasing Stack
To solve the stock span problem efficiently, we can use a monotonic decreasing stack to store the indices of the days. For each day i
, we pop elements from the stack until we find a day with a price greater than the price of the current day. The span for the current day will then be the difference in indices. So,
span[i] = i - ngl(i) if ngl(i) exists otherwise -1
where NGL is nearest greater element on the left of current element. if it exists.
Here is the approach:
- Initialize a stack to keep the indices of the days.
- Initialize an array to store the span values.
- Iterate through the price list:
- For each price, pop elements from the stack until the top of the stack has a price greater than the current price.
- If the stack is empty, it means all previous prices are less than the current price’s price.
- Update the span for the current day.
- Push the current index onto the stack.
- Return the span array.
Code
Java
class Solution {
public int[] calculateSpan(int[] prices) {
int n = prices.length;
int[] span = new int[n];
Stack<Integer> stack = new Stack<>();
for (int i = 0; i < n; i++) {
while (!stack.isEmpty() && prices[stack.peek()] <= prices[i]) {
stack.pop();
}
span[i] = (stack.isEmpty()) ? (i + 1) : (i - stack.peek());
stack.push(i);
}
return span;
}
public static void main(String[] args) {
Solution sol = new Solution();
int[] prices1 = {100, 80, 60, 70, 60, 75, 85};
int[] span1 = sol.calculateSpan(prices1);
for (int sp : span1) {
System.out.print(sp + " ");
}
System.out.println();
int[] prices2 = {10, 4, 5, 90, 120, 80};
int[] span2 = sol.calculateSpan(prices2);
for (int sp : span2) {
System.out.print(sp + " ");
}
}
}
Python
class Solution:
def calculateSpan(self, prices: List[int]) -> List[int]:
n = len(prices)
span = [0] * n
stack = []
for i in range(n):
while stack and prices[stack[-1]] <= prices[i]:
stack.pop()
span[i] = i + 1 if not stack else i - stack[-1]
stack.append(i)
return span
# Example usage
sol = Solution()
prices1 = [100, 80, 60, 70, 60, 75, 85]
span1 = sol.calculateSpan(prices1)
print(span1) # Output: [1, 1, 1, 2, 1, 4, 6]
prices2 = [10, 4, 5, 90, 120, 80]
span2 = sol.calculateSpan(prices2)
print(span2) # Output: [1, 1, 2, 4, 5, 1]
Complexity
- ⏰ Time complexity:
O(n)
as each element is pushed and popped from the stack at most once. - 🧺 Space complexity:
O(n)
for space required for the stack and the resulting span array.
Method 3 - Using NGL solution
This boils down to NGL - Nearest Greater Element to Left of every element
Code
Java
import java.util.Scanner;
import java.util.Stack;
class Solution {
private int[] stockSpanUsingStack(int[] stockPrices) {
int[] NGL = findNearestGreaterToLeftUsingStack(stockPrices);
int[] span = new int[NGL.length];
for(int i = 0; i < NGL.length; i++) {
span[i] = i - NGL[i];
}
return span;
}
}
Complexity
- ⏰ Time complexity:
O(n)
- 🧺 Space complexity:
O(n)