DEV Community

Cover image for ๐Ÿš€ Solving the Stock Span Problem - My Thought Process & Approach
Nesh
Nesh

Posted on

1 1 1 1 1

๐Ÿš€ Solving the Stock Span Problem - My Thought Process & Approach

GFG QUESTION LINK

LEETCODE



๐Ÿ“Œ Problem Statement

Given a series of daily stock prices, we need to find the span of stock price for each day. The span for a day i is defined as the maximum number of consecutive days before (and including) day i for which the stock price is less than or equal to its price on day i.

Example:

Input:  [100, 80, 60, 70, 60, 75, 85]
Output: [1, 1, 1, 2, 1, 4, 6]
Enter fullscreen mode Exit fullscreen mode

๐Ÿ›‘ 1st Attempt: Stack-Based Approach (Inefficient)

๐Ÿ’ก Idea

I initially thought of using a stack to store previous prices, but instead of directly using it, I made a copy of the stack and iterated over it to count the span.

โŒ What went wrong?

  • Copying the stack every time added unnecessary complexity
  • It led to O(nยฒ) complexity and caused TLE (Time Limit Exceeded) on 6 test cases

๐Ÿ”ป Code

class Solution {
  public:
    vector<int> calculateSpan(vector<int>& arr) {
        stack<int> st;
        int n = arr.size();
        vector<int> ans(n);

        for (int i = 0; i < n; i++) {
            int count = 1;
            stack<int> proxy = st; // Copying stack โŒ
            while (!proxy.empty() && proxy.top() < arr[i]) {
                proxy.pop();
                count++;
            }
            ans[i] = count;
            st.push(arr[i]);
        }
        return ans;
    }
};
Enter fullscreen mode Exit fullscreen mode

๐Ÿšจ Issue:

Copying the stack each time resulted in an additional O(n) operation inside a loop, making it O(nยฒ) overall.


๐Ÿ”„ 2nd Attempt: Two-Pointer Approach (Better, but still O(nยฒ))

๐Ÿ’ก Idea

I removed the stack and instead used a backward pointer (j) to find the span for each element.

โŒ What went wrong?

  • Still O(nยฒ) in the worst case (when elements are in increasing order).
  • Failed 1 test case due to TLE (1115/1116 passed).

๐Ÿ”ป Code

class Solution {
  public:
    vector<int> calculateSpan(vector<int>& arr) {
        int n = arr.size();
        vector<int> ans;

        for (int i = 0; i < n; i++) {
            int count = 1;
            int j = i;
            while (j > 0 && arr[j - 1] <= arr[i]) { // Checking all previous elements โŒ
                j--;
                count++;
            }
            ans.push_back(count);
        }
        return ans;
    }
};
Enter fullscreen mode Exit fullscreen mode

๐Ÿšจ Issue:

Although better than the first approach, the worst-case scenario (increasing order of prices) still made it O(nยฒ).


โœ… Final Attempt: Optimized Stack-Based Approach (O(n) Time Complexity)

๐Ÿ’ก Key Insight

Instead of storing only prices, I stored both the price and the count as {price, count} pairs in the stack.

โœจ Why This Works?

  • Instead of iterating over previous elements, we store their spans directly in the stack.
  • When popping elements, we directly add their span count to the current span instead of rechecking them.
  • This ensures O(n) complexity as each element is processed only once.

๐Ÿ”ฅ Final Optimized Code

class Solution {
  public:
    vector<int> calculateSpan(vector<int>& arr) {
        stack<pair<int, int>> st;
        int n = arr.size();
        vector<int> ans(n);

        for (int i = 0; i < n; i++) {
            int count = 1;
            while (!st.empty() && st.top().first <= arr[i]) {
                count += st.top().second;  // Directly add stored counts โœ…
                st.pop();
            }
            st.push({arr[i], count});
            ans[i] = count;
        }
        return ans;
    }
};
Enter fullscreen mode Exit fullscreen mode

๐Ÿš€ Time Complexity: O(n)

Each element is processed only once, making this approach highly efficient.


๐Ÿ”ฅ Key Learnings & Takeaways

1๏ธโƒฃ Avoid redundant operations โ€“ Copying the stack (or unnecessary iterations) adds overhead.

2๏ธโƒฃ Store useful data smartly โ€“ Instead of recalculating spans, storing counts in the stack saved time.

3๏ธโƒฃ Use data structures efficiently โ€“ Leveraging a monotonic stack made the solution significantly faster.


โœจ Conclusion

The journey from O(nยฒ) to O(n) was all about optimizing how we track previous values. Using a stack efficiently made all the difference!

๐Ÿ’ก What do you think about this approach? Have you solved this problem differently? Letโ€™s discuss in the comments! ๐Ÿš€


Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top comments (0)

The Most Contextual AI Development Assistant

Pieces.app image

Our centralized storage agent works on-device, unifying various developer tools to proactively capture and enrich useful materials, streamline collaboration, and solve complex problems through a contextual understanding of your unique workflow.

๐Ÿ‘ฅ Ideal for solo developers, teams, and cross-company projects

Learn more

๐Ÿ‘‹ Kindness is contagious

Engage with a wealth of insights in this thoughtful article, valued within the supportive DEV Community. Coders of every background are welcome to join in and add to our collective wisdom.

A sincere "thank you" often brightens someoneโ€™s day. Share your gratitude in the comments below!

On DEV, the act of sharing knowledge eases our journey and fortifies our community ties. Found value in this? A quick thank you to the author can make a significant impact.

Okay