Exploring Stack-Based Problems and Solutions in Ruby

Introduction to the Lesson

Hello once again, champion of code! In this session, we will delve into the world of coding interviews by focusing on stack-based problems. We endeavor to decode interview questions that leverage the Last-In, First-Out (LIFO) magic of stacks to offer elegantly efficient solutions. After today, not only will you be able to handle stacks with ease, but you'll also be able to articulate and apply this knowledge when faced with interview questions that require depth in data structure understanding.

Problem 1: Preceding Smaller Elements

Imagine a sequence of integers representing the highs and lows of a mountain range. Each integer denotes the height of a peak, and you're moving from left to right, tracking peaks that are shorter than the current one you're standing on. For every peak, the task is to identify the height of the nearest preceding peak that is shorter — a scenario perfectly suited for stacks.

Alternatively, think about monitoring daily temperatures over several months. You're interested in determining the last day when the temperature was cooler for each day you check. This is analogous to finding the previous smaller number for each entry in the array. Stacks excel at handling these types of sequence queries efficiently.

Problem 1: Naive Approach

You might be tempted to approach this problem with the vigor of a brute-force assault — looking behind each element to find a smaller one. However, this could mean reviewing multiple times and spending excessive amounts of time as you consider each element repeatedly. In a vast dataset, this would be akin to retracing your steps on each day's hike to find a shorter peak — an exhausting proposition!

Problem 1: Efficient Approach

Enter the stack — our trusty guide. As we progress through the array, we push peaks onto the stack. When we encounter a peak, we pop entries from the stack that aren't shorter than the current one. The stack's top now reveals the nearest preceding smaller peak, which we note before adding the current peak to the stack.

Problem 1: Solution Building

Let's lace up our boots and start the ascent by iterating through the array of peak heights and interacting with our stack.

def find_preceding_smaller_elements(arr)
  result = []
  stack = []

  arr.each do |current|
    # Pop elements from stack while they are greater than or equal to current
    while !stack.empty? && stack.last >= current
      stack.pop
    end
    # If stack is empty, no smaller element, otherwise append top element
    result << (stack.empty? ? -1 : stack.last)
    stack.push(current)
  end

  result
end

arr = [3, 7, 1, 5, 4, 3]
result = find_preceding_smaller_elements(arr)
puts result.join(" ")  # Output: -1 3 -1 1 1 1

In our code, we trek through each element in the array. Our conditions within the loop perform the 'pop' work — discarding any peak that isn't lower than our current one, ensuring that only useful candidates remain. Then, we notate the result — either -1 if no such peak exists or the last peak remaining on the stack. Before moving on, we add our current peak to the stack.

Sign up

Join the 1M+ learners on CodeSignal

Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal