Given an array arr[] of size 'n' and a positive integer k. Consider series of natural numbers and remove arr[0], arr[1], arr[2], ..., arr[n-1] from it. Now the task is to find k-th smallest number in the remaining set of natural numbers. If no such number exists print "-1".
Examples:
Input: arr[] = [ 1 ] and k = 1.
Output: 2
Explanation: Natural numbers are {1, 2, 3, 4, .... }. After removing {1}, we get {2, 3, 4, ...}. Now, 2-th smallest element = 2.
Input: arr[] = [ 1, 3 ], k = 4.
Output: 6
Explanation: First 5 Natural number {1, 2, 3, 4, 5, 6, .. }. After removing {1, 3}, we get {2, 4, 5, 6, ... }.Now, 4-th smallest element = 6.
[Naive Approach] Using Nested Loops - O(n x k) time and Space
The idea is to run a look for k and run a loop for all array elements inside it. We skip the array elements and increment k if not present in array. Please refer K-th smallest element after removing some integers from natural numbers for implementation
[Expected Approach for Large k] Using Sorting – O(n log n) Time and O(1) Space
- Sort the Removed Elements: First, sort the array of removed numbers in increasing order to process them in the correct sequence.
- Increment k for Each Removed Element: For each number in the sorted array, if it is less than or equal to
k, incrementkbecause the position ofkhas effectively moved forward due to the removal.- Stop When k Is No Longer Affected: If the current removed number is greater than
k, stop the process because no further removals will affect the value ofk.
#include <bits/stdc++.h>
using namespace std;
int findkthSmall(vector<int>& arr, int k) {
sort(arr.begin(), arr.end());
for (int num : arr) {
// increment k because the position of k has
// effectively moved forward due to the removal.
if (num <= k)
k++;
else
break;
}
return k;
}
int main() {
vector<int> arr = {1};
int k = 1;
cout << findkthSmall(arr, k) << endl;
return 0;
}
import java.util.*;
public class GFG {
public static int findKthSmall(List<Integer> arr, int k) {
Collections.sort(arr);
for (int num : arr) {
// Increment k because the position of k has
// effectively moved forward due to the removal.
if (num <= k)
k++;
else
break;
}
return k;
}
public static void main(String[] args) {
List<Integer> arr = Arrays.asList(1);
int k = 1;
System.out.println(findKthSmall(arr, k));
}
}
def findKthSmall(arr, k):
arr.sort()
for num in arr:
# Increment k because the position of k has
# effectively moved forward due to the removal.
if num <= k:
k += 1
else:
break
return k
# Driver code
arr = [1]
k = 1
print(findKthSmall(arr, k))
using System;
using System.Collections.Generic;
class GFG {
public static int findKthSmall(List<int> arr, int k) {
arr.Sort();
foreach (int num in arr) {
// Increment k because the position of k has
// effectively moved forward due to the removal.
if (num <= k)
k++;
else
break;
}
return k;
}
static void Main() {
List<int> arr = new List<int> { 1 };
int k = 1;
Console.WriteLine(findKthSmall(arr, k));
}
}
function findKthSmall(arr, k) {
arr.sort((a, b) => a - b);
for (let num of arr) {
// Increment k because the position of k has
// effectively moved forward due to the removal.
if (num <= k) k++;
else break;
}
return k;
}
let arr = [1];
let k = 1;
console.log(findKthSmall(arr, k));
Output
2
[Expected Approach for Large n] Using Hash Set– O(n + k) Time and O(n) Space
- Store Removed Elements: We store the removed elements in a set for efficient lookup.
- Count Valid Numbers: We iterate over natural numbers, skipping the removed ones, and count how many valid numbers we encounter.
- Return k-th Valid Number: When the valid number count reaches
k, return the current number.
#include <bits/stdc++.h>
using namespace std;
int findKthSmall(vector<int>& arr, int k) {
unordered_set<int> removed(arr.begin(), arr.end());
int cnt = 0, num = 1;
while (cnt < k) {
// Check only valid numbers, skipping removed ones
if (!removed.count(num))
cnt++;
num++;
}
return num - 1;
}
int main() {
vector<int> arr = {1, 3};
cout << findKthSmall(arr, 4) << endl;
return 0;
}
import java.util.*;
public class GFG {
public static int findKthSmall(List<Integer> arr, int k) {
Set<Integer> removed = new HashSet<>(arr);
int cnt = 0, num = 1;
while (cnt < k) {
// Check only valid numbers, skipping removed ones
if (!removed.contains(num))
cnt++;
num++;
}
return num - 1;
}
public static void main(String[] args) {
List<Integer> arr = Arrays.asList(1, 3);
System.out.println(findKthSmall(arr, 4)); // Output: 6
}
}
def findKthSmall(arr, k):
removed = set(arr)
cnt, num = 0, 1
while cnt < k:
# Check only valid numbers,
# skipping removed ones
if num not in removed:
cnt += 1
num += 1
return num - 1
arr = [1, 3]
k = 4
print(findKthSmall(arr, k))
using System;
using System.Collections.Generic;
class GFG {
public static int findKthSmall(List<int> arr, int k) {
HashSet<int> removed = new HashSet<int>(arr);
int cnt = 0, num = 1;
while (cnt < k) {
// Check only valid numbers,
// skipping removed ones
if (!removed.Contains(num))
cnt++;
num++;
}
return num - 1;
}
static void Main() {
List<int> arr = new List<int> {1, 3};
int k = 4;
Console.WriteLine(findKthSmall(arr, k));
}
}
function findKthSmall(arr, k) {
let removed = new Set(arr), cnt = 0, num = 1;
while (cnt < k) {
// Check only valid numbers,
// skipping removed ones
if (!removed.has(num))
cnt++;
num++;
}
return num - 1;
}
let arr = [1, 3];
let k = 4;
console.log(findKthSmall(arr, k));
Output
6