Nearest smaller numbers on left side in an array
Given an array of integers, find the nearest smaller number for every element such that the smaller element is on the left side.
Examples:
Input: arr = [1, 6, 2]
Output: [-1, 1, 1,]
Explanation: There is no number at the left of 1. Smaller number than 6 and 2 is 1.Input: arr = [1, 5, 0, 3, 4, 5]
Output: [-1, 1, -1, 0, 3, 4]
Explanation: Upto 3 it is easy to see the smaller numbers. But for 4 the smaller numbers are 1, 0 and 3. But among them 3 is closest. Similarly for 5 it is 4.
Table of Content
[Naive Approach] Using Nested Loops - O(n^2) Time and O(1) Space
We use two nested loops. The outer loop starts from the second element, the inner loop goes to all elements on the left side of the element picked by the outer loop and stops as soon as it finds a smaller element.
#include <iostream>
#include <vector>
using namespace std;
void prevSmaller(const vector<int>& arr)
{
// Always print -1 for the first element
cout << "-1 ";
// Start from second element
for (int i = 1; i < arr.size(); i++) {
int j;
// Look for a smaller element on the left of 'i'
for (j = i - 1; j >= 0; j--) {
if (arr[j] < arr[i]) {
cout << arr[j] << " ";
break;
}
}
// If there is no smaller element on left of 'i', print -1
if (j == -1)
cout << "-1 ";
}
}
int main()
{
vector<int> arr = {1, 5, 0, 3, 4, 5};
prevSmaller(arr);
return 0;
}
#include <stdio.h>
#include <stdbool.h>
void prevSmaller(int arr[], int size) {
// Always print -1 for the first element
printf("-1 ");
// Start from second element
for (int i = 1; i < size; i++) {
int j;
// Look for a smaller element on the left of 'i'
for (j = i - 1; j >= 0; j--) {
if (arr[j] < arr[i]) {
printf("%d ", arr[j]);
break;
}
}
// If there is no smaller element on left of 'i', print -1
if (j == -1)
printf("-1 ");
}
}
int main() {
int arr[] = {1, 5, 0, 3, 4, 5};
int size = sizeof(arr) / sizeof(arr[0]);
prevSmaller(arr, size);
return 0;
}
import java.util.Arrays;
public class GfG {
public static void prevSmaller(int[] arr) {
// Always print -1 for the first element
System.out.print("-1 ");
// Start from second element
for (int i = 1; i < arr.length; i++) {
int j;
// Look for a smaller element on the left of 'i'
for (j = i - 1; j >= 0; j--) {
if (arr[j] < arr[i]) {
System.out.print(arr[j] + " ");
break;
}
}
// If there is no smaller element on left of 'i', print -1
if (j == -1)
System.out.print("-1 ");
}
}
public static void main(String[] args) {
int[] arr = {1, 5, 0, 3, 4, 5};
prevSmaller(arr);
}
}
def prevSmaller(arr):
# Always print -1 for the first element
print("-1", end=' ')
# Start from second element
for i in range(1, len(arr)):
# Look for a smaller element on the left of 'i'
for j in range(i - 1, -1, -1):
if arr[j] < arr[i]:
print(arr[j], end=' ')
break
else:
# If there is no smaller element on left of 'i', print -1
print("-1", end=' ')
arr = [1, 5, 0, 3, 4, 5]
prevSmaller(arr)
using System;
class GfG {
static void PrevSmaller(int[] arr) {
// Always print -1 for the first element
Console.Write("-1 ");
// Start from second element
for (int i = 1; i < arr.Length; i++) {
int j;
// Look for a smaller element on the left of 'i'
for (j = i - 1; j >= 0; j--) {
if (arr[j] < arr[i]) {
Console.Write(arr[j] + " ");
break;
}
}
// If there is no smaller element on left of 'i', print -1
if (j == -1)
Console.Write("-1 ");
}
}
static void Main() {
int[] arr = {1, 5, 0, 3, 4, 5};
PrevSmaller(arr);
}
}
function prevSmaller(arr) {
// Always print -1 for the first element
process.stdout.write("-1 ");
// Start from second element
for (let i = 1; i < arr.length; i++) {
let found = false;
// Look for a smaller element on the left of 'i'
for (let j = i - 1; j >= 0; j--) {
if (arr[j] < arr[i]) {
process.stdout.write(` ${arr[j]}`);
found = true;
break;
}
}
// If there is no smaller element on left of 'i', print -1
if (!found)
process.stdout.write(" -1");
}
}
const arr = [1, 5, 0, 3, 4, 5];
prevSmaller(arr);
Output
-1 1 -1 0 3 4
[Expected Approach] Using Stack- O(n) Time and O(n) Space
If we traverse the array from left to right, then for the current element, there can be two cases.
1) The element is greater than the previous element, then the nearest smaller for current element is the previous element,
2) The element is smaller than the previous element. In this case, the smaller element can be anywhere. But one thing to note is that the previous elements that are greater than the current element are never going to smaller elements for any of the upcoming elements and hence need not to be stored.The idea is to use a stack to store the potential smaller elements that we have seen so far. We use stack (LIFO) as we need the most recently seen smaller. We remove top of the stack one by one while the top is greater than the current element. When we find a smaller element, we print it. One important observation is, the stack will always have elements in increasing order as we remove greater elements before pushing.
1. Create a new empty stack s
.
2. Iterate over each element arr[i]
in the array arr[]
(from 0 to n-1).
- While the stack
s
is non-empty and the top element of the stack is greater than or equal toarr[i]
, pop the stack. This ensures that we are left with only the elements in the stack that are smaller thanarr[i]
. - If the stack is empty after popping, then
arr[i]
has no preceding smaller element. In this case, print-1
. - If the stack is not empty, the nearest smaller element to
arr[i]
is the top element of the stack. Print the top element. - Push
arr[i]
onto the stack for future comparisons.
#include <iostream>
#include <vector>
#include <stack>
using namespace std;
void prevSmaller(vector<int>& arr)
{
stack<int> s;
for (int i = 0; i < arr.size(); i++)
{
while (!s.empty() && s.top() >= arr[i])
s.pop();
if (s.empty())
cout << "-1 ";
else
cout << s.top() << " ";
s.push(arr[i]);
}
}
int main()
{
vector<int> arr = {1, 5, 0, 3, 4, 5};
prevSmaller(arr);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
void prevSmaller(int* arr, int n) {
int* s = (int*)malloc(n * sizeof(int));
int top = -1;
for (int i = 0; i < n; i++) {
while (top != -1 && s[top] >= arr[i])
top--;
if (top == -1)
printf("-1 ");
else
printf("%d ", s[top]);
s[++top] = arr[i];
}
free(s);
}
int main() {
int arr[] = {1, 5, 0, 3, 4, 5};
int n = sizeof(arr) / sizeof(arr[0]);
prevSmaller(arr, n);
return 0;
}
import java.util.Stack;
public class GfG {
public static void prevSmaller(int[] arr) {
Stack<Integer> s = new Stack<>();
for (int i = 0; i < arr.length; i++) {
while (!s.isEmpty() && s.peek() >= arr[i])
s.pop();
if (s.isEmpty())
System.out.print("-1 ");
else
System.out.print(s.peek() + " ");
s.push(arr[i]);
}
}
public static void main(String[] args) {
int[] arr = {1, 5, 0, 3, 4, 5};
prevSmaller(arr);
}
}
def prev_smaller(arr):
s = []
for i in range(len(arr)):
while s and s[-1] >= arr[i]:
s.pop()
if not s:
print(-1, end=' ')
else:
print(s[-1], end=' ')
s.append(arr[i])
if __name__ == '__main__':
arr = [1, 5, 0, 3, 4, 5]
prev_smaller(arr)
using System;
using System.Collections.Generic;
class GfG {
public static void PrevSmallerElements(int[] arr) {
Stack<int> s = new Stack<int>();
for (int i = 0; i < arr.Length; i++) {
while (s.Count > 0 && s.Peek() >= arr[i])
s.Pop();
if (s.Count == 0)
Console.Write("-1 ");
else
Console.Write(s.Peek() + " ");
s.Push(arr[i]);
}
}
static void Main() {
int[] arr = {1, 5, 0, 3, 4, 5};
PrevSmallerElements(arr);
}
}
function prevSmaller(arr) {
const s = [];
arr.forEach((num) => {
while (s.length && s[s.length - 1] >= num) {
s.pop();
}
if (s.length === 0) {
process.stdout.write("-1 ");
} else {
process.stdout.write(s[s.length - 1] + " ");
}
s.push(num);
});
}
const arr = [1, 5, 0, 3, 4, 5];
prevSmaller(arr);
Output
-1 1 -1 0 3 4