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


Image of Datadog

Get the real story behind DevSecOps

Explore data from thousands of apps to uncover how container image size, deployment frequency, and runtime context affect real-world security. Discover seven key insights that can help you build and ship more secure software.

Read the Report

Top comments (0)

Image of Datadog

Keep your GPUs in check

This cheatsheet shows how to use Datadogโ€™s NVIDIA DCGM and Triton integrations to track GPU health, resource usage, and model performanceโ€”helping you optimize AI workloads and avoid hardware bottlenecks.

Get the Cheatsheet

๐Ÿ‘‹ 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