Problem Statement
Given an array of integers, the task is to find the second smallest and second largest elements present in the array.
Examples
Example 1:
Input: [1,2,4,7,7,5]
Output: Second Smallest : 2
Second Largest : 5
Explanation: The elements are as follows 1,2,3,5,7,7 and hence second largest of these is 5 and second smallest is 2
Example 2:
Input: [1]
Output: Second Smallest : -1
Second Largest : -1
Explanation: Since there is only one element in the array, it is the largest and smallest element present in the array. There is no second largest or second smallest element present.
Example 3:
Input: [5, 5, 5, 5, 5]
Output: Second Smallest : -1
Second Largest : -1
Explanation: Since all the elements in the array are same, so there is no second smallest or second largest element.
Different Approaches
1️⃣ Brute Force Approach: (this approach only works if there are no duplicates)
Sorting the array in increasing order allows us to easily identify the second smallest and second largest elements. Once the array is sorted, the second smallest element will be at index 1
, and the second largest element will be at index n - 2
, where n
is the size of the array.
Algorithm:
- Sort the array in non-decreasing order.
- The second smallest element will be at index1 (
arr[1]
), and the second largest element will be at indexn - 2
(arr[n - 2]
), wheren
is the size of the array.
Code:
#include<bits/stdc++.h>
using namespace std;
void getElements(int arr[],int n)
{
if(n==0 || n==1)
cout<<-1<<" "<<-1<<endl; // edge case when only one element is present in array
sort(arr,arr+n);
int small=arr[1];
int large=arr[n-2];
cout<<"Second smallest is "<<small<<endl;
cout<<"Second largest is "<<large<<endl;
}
int main()
{
int arr[]={1,2,4,6,7,5};
int n=sizeof(arr)/sizeof(arr[0]);
getElements(arr,n);
return 0;
}
Complexity Analysis:
- Time Complexity:
O(n log n)
due to sorting. - Space Complexity:
O(1)
if sorting is done in place.
2️⃣ Better Solution
Algorithm:
- Find the smallest and largest element in the array in a single traversal.
- After this, we once again find the largest element however which is smaller than the largest element which we found in first traversal.
- Similarly, we would find the second smallest element which is just larger than the smallest element from the first traversal.
Code:
#include<bits/stdc++.h>
using namespace std;
void getElements(int arr[],int n)
{
if(n==0 || n==1)
cout<<-1<<" "<<-1<<endl; // edge case when only one element is present in array
int small=INT_MAX,second_small=INT_MAX;
int large=INT_MIN,second_large=INT_MIN;
int i;
for(i=0;i<n;i++)
{
small=min(small,arr[i]);
large=max(large,arr[i]);
}
for(i=0;i<n;i++)
{
if(arr[i]<second_small && arr[i]!=small)
second_small=arr[i];
if(arr[i]>second_large && arr[i]!=large)
second_large=arr[i];
}
cout<<"Second smallest is "<<second_small<<endl;
cout<<"Second largest is "<<second_large<<endl;
}
int main()
{
int arr[]={1,2,4,6,7,5};
int n=sizeof(arr)/sizeof(arr[0]);
getElements(arr,n);
return 0;
}
// Output
Second smallest is 2
Second largest is 6
Complexity Analysis
Time Complexity:
- The first loop iterates through the array once to find the smallest and largest elements. This requires
O(n)
time. - The second loop also iterates through the array once to find the second smallest and second largest elements. This also requires
O(n)
time. - Therefore, the overall time complexity of this approach is
O(n + n)
, which is simplifies toO(2n)
, orO(n)
when considering the dominant term.
Space Complexity:
- The space complexity of this approach remains
O(1)
as it only uses a constant amount of extra space to store variables.
3️⃣ Optimal Approach
The time complexity was reduced to O(n)
in the previous approach, but still involved two separate traversal of the array, which may not be the most efficient solution, especially for large arrays.
To optimize the solution further and reduce it to single traversal, we can use a slightly different strategy. We can maintain four variables to keep track of the smallest, second smallest, largest, and second largest elements as we traverse the array one.
Algorithm:
- Initialize four variables:
smallest
,second_smallest
,largest
, andsecond_largest
, with initial values set to the maximum and minimum possible integer values, respectively. - Iterate through the array:
- For each element
arr[i]
:- If
arr[i]
is smaller thansmallest
, update bothsecond_smallest
andsmallest
. - Otherwise, if
arr[i]
is smaller thansecond_smallest
andarr[i]
is not equal tosmallest
, updatesecond_smallest
only. - If
arr[i]
is larger thanlargest
, update bothsecond_largest
andlargest
. - Otherwise, if
arr[i]
is larger thansecond_largest
andarr[i]
is not equal tolargest
, updatesecond_largest
only.
- If
- For each element
- After iterating through the entire array, the variables
second_smallest
andsecond_largest
will contain the second smallest and second largest elements, respectively. - Output the values of
second_smallest
andsecond_largest
.
Code:
#include <iostream>
#include <climits> // For INT_MAX and INT_MIN
using namespace std;
void findSecondLargestAndSmallest(int arr[], int n) {
// Initializing the variables
int smallest = INT_MAX, second_smallest = INT_MAX;
int largest = INT_MIN, second_largest = INT_MIN;
if (n < 2) {
cout << "Array needs to have at least two elements." << endl;
return;
}
for (int i = 0; i < n; ++i) {
// Finding smallest and second smallest
if (arr[i] < smallest) {
second_smallest = smallest;
smallest = arr[i];
} else if (arr[i] < second_smallest && arr[i] != smallest) {
second_smallest = arr[i];
}
// Finding largest and second largest
if (arr[i] > largest) {
second_largest = largest;
largest = arr[i];
} else if (arr[i] > second_largest && arr[i] != largest) {
second_largest = arr[i];
}
}
// Checking if we found valid second smallest and second largest
if (second_smallest == INT_MAX) {
cout << "There is no second smallest element." << endl;
} else {
cout << "The second smallest element is: " << second_smallest << endl;
}
if (second_largest == INT_MIN) {
cout << "There is no second largest element." << endl;
} else {
cout << "The second largest element is: " << second_largest << endl;
}
}
int main() {
int arr[] = {12, 35, 1, 10, 35, 1};
int n = sizeof(arr) / sizeof(arr[0]);
findSecondLargestAndSmallest(arr, n);
return 0;
}
Complexity Analysis
- Time Complexity: The time complexity of this algorithm is
O(n)
, wheren
is the number of elements in the array. This is because we only traverse the array once. - Space Complexity: The space complexity of this algorithm is
O(1)
, as we only use a constant amount of extra space to store the variablessmallest
,second_smallest
,largest
, andsecond_largest
.