I attempted to solve the kth smallest number problem and came up with a slightly alternative solution from how it suggests I was meant to solve the problem. However, from running some tests, I think the solution I came up with is faster (in terms of time complexity).
I didn’t particularly like my solution because it felt slightly hacky, but from my tests it feels like it is performing better. Have I just miscalculated this, or have I stumbled upon a more efficient solution?
My code is as follows:
public static int kSmallestNumber(List<List> lists, int k) {
int numberOfLists = lists.size();
// Maintain a list of pointers for each list to keep track of where we are
int[] pointers = new int[numberOfLists];
// Keep track of the currentSmallest number, and which array it's in
int currentSmallest = 0;
int prevSmallest = 0;
int kthNumber = 0;
int currentSmallestArray = 0;
// Iterate k times
while (kthNumber != k) {
currentSmallest = Integer.MAX_VALUE;
// Iterate over each list
for (int i = 0; i < numberOfLists; i++) {
if (pointers[i] > lists.get(i).size() - 1) {
// If this list has already been exhausted, then continue
continue;
}
int tempCurrentNumber = lists.get(i).get(pointers[i]);
if (tempCurrentNumber <= currentSmallest) {
// As we iterate, keep track of the next smallest number and which list it's in
currentSmallest = tempCurrentNumber;
currentSmallestArray = i;
prevSmallest = tempCurrentNumber;
}
}
// Increment the pointer for the array which had the smallest number so don't compare this number again
pointers[currentSmallestArray] +=1;
kthNumber++;
}
// Return the smallest number if it isn't max value (if the value of k is larger than all the list sizes)
// Otherwise return the previous largest number
return currentSmallest == Integer.MAX_VALUE ? prevSmallest : currentSmallest;
}
And the provided solution is as follows:
public static int kSmallestNumber2(List<List> lists, int k) {
// storing the length of lists to use it in a loop later
int listLength = lists.size();
// declaring a min-heap to keep track of smallest elements
PriorityQueue<int[]> kthSmallest = new PriorityQueue<>((a, b) → a[0] - b[0]);
for (int index = 0; index < listLength; index++) {
// if there are no elements in the input lists, continue
if (lists.get(index).size() == 0) {
continue;
} else {
// placing the first element of each list in the min-heap
kthSmallest.offer(new int[]{lists.get(index).get(0), index, 0});
}
}
// set a counter to match if our kth element
// equals to that counter, return that number
int numbersChecked = 0, smallestNumber = 0;
while (!kthSmallest.isEmpty()) { // iterating over the elements pushed in our min-heap
// get the smallest number from top of heap and its corresponding list and index
int[] smallest = kthSmallest.poll();
smallestNumber = smallest[0];
int listIndex = smallest[1];
int numIndex = smallest[2];
numbersChecked++;
if (numbersChecked == k) {
break;
}
// if there are more elements in list of the top element,
// add the next element of that list to the min-heap
if (numIndex + 1 < lists.get(smallest[1]).size()) {
kthSmallest.offer(new int[]{lists.get(listIndex).get(numIndex + 1), listIndex, numIndex + 1});
}
}
// return the Kth number found in input lists
return smallestNumber;
}
Thank you for any help!
Course: Grokking Coding Interview Patterns in Java - Learn Interactively
Lesson: Kth Smallest Number in M Sorted Lists
Course: Grokking Coding Interview Patterns in Java - Learn Interactively
Lesson: Kth Smallest Number in M Sorted Lists