Previous Smaller Element for Each Array Position
Solve this Problemarr, find, for every position, the value of the nearest element strictly smaller than it to its left — or -1 if no such element exists.
Scanning backward from every position independently works but repeats a lot of comparisons that a smarter approach can skip entirely. The key insight: once a smaller value appears, every larger value sitting behind it becomes permanently irrelevant — no future position will ever "see past" the smaller, closer value to reach them. A monotonic stackMonotonic StackA stack maintained so its values stay in strictly increasing (or decreasing) order from bottom to top. Before pushing a new value, anything on top that would break that order gets popped off first — those popped values are provably never useful again. exploits exactly that: keep only values in increasing order, discarding anything that a smaller arrival has made obsolete, and whatever survives on top at each step is precisely the answer.
Test Case 1:
Test Case 2:
Test Case 3:
Constraints
- ◆
1 ≤ arr.length ≤ 15 - ◆
0 ≤ arr[i] ≤ 1000
Try the Dry Run
Don't just read the solution — watch it execute, one step at a time.
Approach & Solutions
Brute Force — Scan Backward for Each Position
BruteFor every position i, scan backward from i-1 toward the start, looking for the first value smaller than arr[i]. The first one found (closest to i) is the answer; if the scan reaches the beginning without finding one, the answer is -1. Correct, but each position can trigger a scan through nearly the whole array before it — O(n) per position, O(n²) overall.
O(n²)O(n)1class Solution {
2 public int[] previousSmallerElement(int[] arr) {
3 int n = arr.length;
4 int[] result = new int[n];
5 for (int i = 0; i < n; i++) {
6 result[i] = -1;
7 for (int j = i - 1; j >= 0; j--) {
8 if (arr[j] < arr[i]) {
9 result[i] = arr[j];
10 break;
11 }
12 }
13 }
14 return result;
15 }
16}Optimal — Monotonic Increasing Stack
OptimalKeep a stack that only ever holds values in increasing order from bottom to top. For each new element, first pop off anything on top that's greater than or equal to it — those values can never be the answer for this or any later element, since the current element is smaller and closer. Whatever's left on top after popping (if anything) is exactly the nearest smaller element to the left. Push the current value and move on. Every value is pushed once and popped at most once, so the total work across the whole array is O(n).
O(n)O(n)1class Solution {
2 public int[] previousSmallerElement(int[] arr) {
3 int n = arr.length;
4 int[] result = new int[n];
5 Deque<Integer> stack = new ArrayDeque<>();
6 for (int i = 0; i < n; i++) {
7 while (!stack.isEmpty() && stack.peek() >= arr[i]) {
8 stack.pop();
9 }
10 result[i] = stack.isEmpty() ? -1 : stack.peek();
11 stack.push(arr[i]);
12 }
13 return result;
14 }
15}