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! ๐Ÿš€


Heroku

Amplify your impact where it matters most โ€” building exceptional apps.

Leave the infrastructure headaches to us, while you focus on pushing boundaries, realizing your vision, and making a lasting impression on your users.

Get Started

Top comments (0)

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

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