1+ # Next Greater Element Problem - Stack Implementation
2+ #
3+ # Problem Statement:
4+ # Given an array of integers, for each element find the next greater element to its right.
5+ # The next greater element for an element x is the first greater element on the right side of x.
6+ # If no greater element exists, return -1 for that element.
7+ #
8+ # Examples:
9+ # Input: [4, 5, 2, 25]
10+ # Output: [5, 25, 25, -1]
11+ # Explanation:
12+ # - For 4, next greater is 5
13+ # - For 5, next greater is 25
14+ # - For 2, next greater is 25
15+ # - For 25, no greater element exists
16+ #
17+ # Input: [13, 7, 6, 12]
18+ # Output: [-1, 12, 12, -1]
19+ #
20+ # Input: [1, 3, 2, 4]
21+ # Output: [3, 4, 4, -1]
22+ #
23+ # Algorithm: Stack-based O(n) solution
24+ # Time Complexity: O(n) - each element is pushed and popped at most once
25+ # Space Complexity: O(n) - for the stack in worst case (decreasing sequence)
26+
27+ # Simple Stack implementation for algorithm use
28+ AlgorithmStack <- setRefClass(" AlgorithmStack" ,
29+ fields = list (
30+ items = " list" ,
31+ top_idx = " numeric"
32+ ),
33+ methods = list (
34+ initialize = function () {
35+ .self $ items <- list ()
36+ .self $ top_idx <- 0
37+ },
38+
39+ push = function (item ) {
40+ .self $ top_idx <- .self $ top_idx + 1
41+ .self $ items [[.self $ top_idx ]] <- item
42+ },
43+
44+ pop = function () {
45+ if (.self $ top_idx == 0 ) return (NULL )
46+ item <- .self $ items [[.self $ top_idx ]]
47+ .self $ top_idx <- .self $ top_idx - 1
48+ return (item )
49+ },
50+
51+ peek = function () {
52+ if (.self $ top_idx == 0 ) return (NULL )
53+ return (.self $ items [[.self $ top_idx ]])
54+ },
55+
56+ is_empty = function () {
57+ return (.self $ top_idx == 0 )
58+ },
59+
60+ size = function () {
61+ return (.self $ top_idx )
62+ }
63+ )
64+ )
65+
66+ # Main function to find next greater elements
67+ next_greater_element <- function (arr ) {
68+ " Find next greater element for each element in array using stack"
69+ if (length(arr ) == 0 ) return (c())
70+
71+ n <- length(arr )
72+ result <- rep(- 1 , n ) # Initialize all with -1
73+ stack <- AlgorithmStack $ new()
74+
75+ # Process each element from left to right
76+ for (i in 1 : n ) {
77+ # While stack is not empty and current element is greater than
78+ # the element at index stored at top of stack
79+ while (! stack $ is_empty() && arr [i ] > arr [stack $ peek()]) {
80+ index <- stack $ pop()
81+ result [index ] <- arr [i ]
82+ }
83+
84+ # Push current element's index to stack
85+ stack $ push(i )
86+ }
87+
88+ return (result )
89+ }
90+
91+ # Enhanced version with step-by-step visualization
92+ next_greater_element_with_steps <- function (arr ) {
93+ " Find next greater elements with detailed step-by-step visualization"
94+ if (length(arr ) == 0 ) return (list (result = c(), steps = list ()))
95+
96+ n <- length(arr )
97+ result <- rep(- 1 , n )
98+ stack <- AlgorithmStack $ new()
99+ steps <- list ()
100+
101+ # Initial state
102+ steps [[1 ]] <- list (
103+ step = 0 ,
104+ current_element = " Start" ,
105+ array = arr ,
106+ stack_contents = c(),
107+ result = result ,
108+ description = " Initial state"
109+ )
110+
111+ for (i in 1 : n ) {
112+ step_description <- paste(" Processing element" , arr [i ], " at index" , i )
113+
114+ # Pop elements and update result
115+ popped_elements <- c()
116+ while (! stack $ is_empty() && arr [i ] > arr [stack $ peek()]) {
117+ index <- stack $ pop()
118+ result [index ] <- arr [i ]
119+ popped_elements <- c(popped_elements , index )
120+ }
121+
122+ if (length(popped_elements ) > 0 ) {
123+ step_description <- paste(step_description , " | Found NGE for indices:" , paste(popped_elements , collapse = " , " ))
124+ }
125+
126+ # Push current index
127+ stack $ push(i )
128+
129+ # Get current stack contents for visualization
130+ stack_contents <- c()
131+ if (! stack $ is_empty()) {
132+ for (j in 1 : stack $ size()) {
133+ if (j < = length(stack $ items )) {
134+ stack_contents <- c(stack_contents , stack $ items [[j ]])
135+ }
136+ }
137+ }
138+
139+ # Record step
140+ steps [[i + 1 ]] <- list (
141+ step = i ,
142+ current_element = arr [i ],
143+ array = arr ,
144+ stack_contents = stack_contents ,
145+ result = result ,
146+ description = step_description
147+ )
148+ }
149+
150+ return (list (result = result , steps = steps ))
151+ }
152+
153+ # Helper function to print array nicely
154+ print_array <- function (arr , title = " Array" ) {
155+ cat(title , " : [" , paste(arr , collapse = " , " ), " ]\n " )
156+ }
157+
158+ # Helper function to print step visualization
159+ print_step <- function (step_info ) {
160+ cat(" \n Step" , step_info $ step , " :" , step_info $ description , " \n " )
161+ cat(" Current element:" , step_info $ current_element , " \n " )
162+ print_array(step_info $ array , " Input" )
163+
164+ if (length(step_info $ stack_contents ) > 0 ) {
165+ stack_values <- sapply(step_info $ stack_contents , function (idx ) paste0(step_info $ array [idx ], " (" , idx , " )" ))
166+ cat(" Stack (indices): [" , paste(stack_values , collapse = " , " ), " ]\n " )
167+ } else {
168+ cat(" Stack: [empty]\n " )
169+ }
170+
171+ print_array(step_info $ result , " Result so far" )
172+ }
173+
174+ # Next Greater Element to the Right for Circular Array
175+ next_greater_element_circular <- function (arr ) {
176+ " Find next greater elements in circular array (wrapping around)"
177+ if (length(arr ) == 0 ) return (c())
178+
179+ n <- length(arr )
180+ result <- rep(- 1 , n )
181+ stack <- AlgorithmStack $ new()
182+
183+ # Process the array twice to handle circular nature
184+ for (i in 1 : (2 * n )) {
185+ current_index <- ((i - 1 ) %% n ) + 1 # Convert to 1-based circular index
186+
187+ while (! stack $ is_empty() && arr [current_index ] > arr [stack $ peek()]) {
188+ index <- stack $ pop()
189+ if (result [index ] == - 1 ) { # Only update if not already found
190+ result [index ] <- arr [current_index ]
191+ }
192+ }
193+
194+ if (i < = n ) { # Only push indices in first pass
195+ stack $ push(current_index )
196+ }
197+ }
198+
199+ return (result )
200+ }
201+
202+ # Previous Greater Element (using stack)
203+ previous_greater_element <- function (arr ) {
204+ " Find previous greater element for each element"
205+ if (length(arr ) == 0 ) return (c())
206+
207+ n <- length(arr )
208+ result <- rep(- 1 , n )
209+ stack <- AlgorithmStack $ new()
210+
211+ # Process from left to right
212+ for (i in 1 : n ) {
213+ # Remove smaller or equal elements
214+ while (! stack $ is_empty() && arr [stack $ peek()] < = arr [i ]) {
215+ stack $ pop()
216+ }
217+
218+ # If stack is not empty, top element is previous greater
219+ if (! stack $ is_empty()) {
220+ result [i ] <- arr [stack $ peek()]
221+ }
222+
223+ stack $ push(i )
224+ }
225+
226+ return (result )
227+ }
228+
229+ # Stock Span Problem using Stack
230+ stock_span <- function (prices ) {
231+ " Calculate stock span for each day (consecutive previous days with price <= current day)"
232+ if (length(prices ) == 0 ) return (c())
233+
234+ n <- length(prices )
235+ spans <- rep(1 , n ) # Initialize all spans to 1
236+ stack <- AlgorithmStack $ new()
237+
238+ for (i in 1 : n ) {
239+ # Pop elements while stack is not empty and
240+ # price at stack top is less than or equal to current price
241+ while (! stack $ is_empty() && prices [stack $ peek()] < = prices [i ]) {
242+ stack $ pop()
243+ }
244+
245+ # If stack becomes empty, span is i (all previous days)
246+ # Otherwise, span is difference between current index and index at stack top
247+ spans [i ] <- if (stack $ is_empty()) i else (i - stack $ peek())
248+
249+ # Push current index to stack
250+ stack $ push(i )
251+ }
252+
253+ return (spans )
254+ }
255+
256+ # Largest Rectangle in Histogram using Stack
257+ largest_rectangle_histogram <- function (heights ) {
258+ " Find the largest rectangle area in histogram using stack"
259+ if (length(heights ) == 0 ) return (0 )
260+
261+ n <- length(heights )
262+ stack <- AlgorithmStack $ new()
263+ max_area <- 0
264+
265+ for (i in 1 : n ) {
266+ # While stack is not empty and current height is less than
267+ # height at stack top, calculate area with stack top as smallest bar
268+ while (! stack $ is_empty() && heights [i ] < heights [stack $ peek()]) {
269+ height <- heights [stack $ pop()]
270+ width <- if (stack $ is_empty()) i - 1 else i - stack $ peek() - 1
271+ area <- height * width
272+ max_area <- max(max_area , area )
273+ }
274+ stack $ push(i )
275+ }
276+
277+ # Process remaining bars in stack
278+ while (! stack $ is_empty()) {
279+ height <- heights [stack $ pop()]
280+ width <- if (stack $ is_empty()) n else n - stack $ peek()
281+ area <- height * width
282+ max_area <- max(max_area , area )
283+ }
284+
285+ return (max_area )
286+ }
287+
288+ # Function to demonstrate all stack applications
289+ demonstrate_stack_applications <- function () {
290+ cat(" === Stack Applications - Problem Solving ===\n " )
291+
292+ # Test Case 1: Next Greater Element
293+ cat(" \n --- Next Greater Element Problem ---\n " )
294+ test_arrays <- list (
295+ c(4 , 5 , 2 , 25 ),
296+ c(13 , 7 , 6 , 12 ),
297+ c(1 , 3 , 2 , 4 ),
298+ c(5 , 4 , 3 , 2 , 1 ),
299+ c(1 , 2 , 3 , 4 , 5 )
300+ )
301+
302+ for (i in seq_along(test_arrays )) {
303+ arr <- test_arrays [[i ]]
304+ result <- next_greater_element(arr )
305+ cat(" \n Test" , i , " :\n " )
306+ print_array(arr , " Input" )
307+ print_array(result , " Next Greater" )
308+ }
309+
310+ # Test Case 2: Circular Array
311+ cat(" \n --- Next Greater Element (Circular Array) ---\n " )
312+ circular_test <- c(1 , 2 , 1 )
313+ print_array(circular_test , " Input" )
314+ circular_result <- next_greater_element_circular(circular_test )
315+ print_array(circular_result , " Next Greater (Circular)" )
316+
317+ # Test Case 3: Previous Greater Element
318+ cat(" \n --- Previous Greater Element ---\n " )
319+ prev_test <- c(4 , 5 , 2 , 25 , 7 , 8 )
320+ print_array(prev_test , " Input" )
321+ prev_result <- previous_greater_element(prev_test )
322+ print_array(prev_result , " Previous Greater" )
323+
324+ # Test Case 4: Stock Span Problem
325+ cat(" \n --- Stock Span Problem ---\n " )
326+ stock_prices <- c(100 , 80 , 60 , 70 , 60 , 75 , 85 )
327+ print_array(stock_prices , " Stock Prices" )
328+ span_result <- stock_span(stock_prices )
329+ print_array(span_result , " Stock Spans" )
330+ cat(" Explanation: Span[i] = number of consecutive days (including current) with price <= price[i]\n " )
331+
332+ # Test Case 5: Largest Rectangle in Histogram
333+ cat(" \n --- Largest Rectangle in Histogram ---\n " )
334+ histogram_heights <- c(6 , 2 , 5 , 4 , 5 , 1 , 6 )
335+ print_array(histogram_heights , " Histogram Heights" )
336+ max_area <- largest_rectangle_histogram(histogram_heights )
337+ cat(" Largest Rectangle Area:" , max_area , " \n " )
338+ }
339+
340+ # Detailed step-by-step demonstration
341+ demonstrate_detailed_steps <- function () {
342+ cat(" \n\n === Detailed Step-by-Step: Next Greater Element ===\n " )
343+
344+ test_array <- c(4 , 5 , 2 , 25 )
345+ cat(" \n Solving for array:" , paste(test_array , collapse = " , " ), " \n " )
346+ cat(" Algorithm: Use stack to store indices of elements for which NGE is not found yet\n " )
347+
348+ solution <- next_greater_element_with_steps(test_array )
349+
350+ for (step in solution $ steps ) {
351+ print_step(step )
352+ }
353+
354+ cat(" \n Final Result:" , paste(solution $ result , collapse = " , " ), " \n " )
355+ cat(" \n Time Complexity: O(n) - each element pushed and popped at most once\n " )
356+ cat(" Space Complexity: O(n) - for the stack in worst case\n " )
357+ }
358+
359+ # Run demonstrations if script is executed directly
360+ if (sys.nframe() == 0 ) {
361+ demonstrate_stack_applications()
362+ demonstrate_detailed_steps()
363+ }
0 commit comments