Find the Kth Largest Integer in the Array
Problem
You are given an array of strings nums and an integer k. Each string in nums represents an integer without leading zeros.
Return the string that represents thekth _largest integer in _nums.
Note : Duplicate numbers should be counted distinctly. For example, if nums is ["1","2","2"], "2" is the first largest integer, "2" is the second-largest integer, and "1" is the third-largest integer.
Examples
Example 1
Input: nums = ["3","6","7","10"], k = 4
Output: "3"
Explanation:
The numbers in nums sorted in non-decreasing order are ["3","6","7","10"].
The 4th largest integer in nums is "3".
Example 2
Input: nums = ["2","21","12","1"], k = 3
Output: "2"
Explanation:
The numbers in nums sorted in non-decreasing order are ["1","2","12","21"].
The 3rd largest integer in nums is "2".
Example 3
Input: nums = ["0","0"], k = 2
Output: "0"
Explanation:
The numbers in nums sorted in non-decreasing order are ["0","0"].
The 2nd largest integer in nums is "0".
Constraints
1 <= k <= nums.length <= 10^41 <= nums[i].length <= 100nums[i]consists of only digits.nums[i]will not have any leading zeros.
Similar Problems
- [Kth Largest Element in an Array](kth-largest-element-in-an-array)
Solution
Method 1 – Custom Sorting
Intuition
Since the numbers are represented as strings and can be very large, we cannot convert them to integers directly. To compare two numbers as strings, compare their lengths first; if equal, compare lexicographically. Sorting the array with this custom comparator allows us to find the k-th largest easily.
We need to custom our comparator since the default comparator is string comparator which compares by lexicographically order, it means for example: "123" < "14".
Approach
- Sort the array of strings in descending order using a custom comparator:
- If the lengths differ, the longer string is larger.
- If the lengths are equal, compare lexicographically.
- Return the string at index
k-1after sorting.
Code
C++
class Solution {
public:
string kthLargestNumber(vector<string>& nums, int k) {
sort(nums.begin(), nums.end(), [](const string& a, const string& b) {
return a.size() == b.size() ? a > b : a.size() > b.size();
});
return nums[k-1];
}
};
Go
func kthLargestNumber(nums []string, k int) string {
sort.Slice(nums, func(i, j int) bool {
if len(nums[i]) != len(nums[j]) {
return len(nums[i]) > len(nums[j])
}
return nums[i] > nums[j]
})
return nums[k-1]
}
Java
class Solution {
public String kthLargestNumber(String[] nums, int k) {
Arrays.sort(nums, (a, b) -> a.length() == b.length() ? b.compareTo(a) : b.length() - a.length());
return nums[k-1];
}
}
Kotlin
class Solution {
fun kthLargestNumber(nums: Array<String>, k: Int): String {
nums.sortWith(compareByDescending<String> { it.length }.thenByDescending { it })
return nums[k-1]
}
}
Python
class Solution:
def kthLargestNumber(self, nums: list[str], k: int) -> str:
nums.sort(key=lambda x: (len(x), x), reverse=True)
return nums[k-1]
Rust
impl Solution {
pub fn kth_largest_number(nums: Vec<String>, k: i32) -> String {
let mut nums = nums;
nums.sort_by(|a, b| b.len().cmp(&a.len()).then(b.cmp(a)));
nums[(k-1) as usize].clone()
}
}
TypeScript
class Solution {
kthLargestNumber(nums: string[], k: number): string {
nums.sort((a, b) => b.length - a.length || b.localeCompare(a));
return nums[k-1];
}
}
Complexity
- ⏰ Time complexity:
O(n log n * m), where n is the number of strings and m is the average length, due to sorting with custom comparator. - 🧺 Space complexity:
O(n * m), for storing the strings and sorting.
Method 2 – Using Min Heap
Intuition
Rather than sorting the entire array, we can maintain a min heap of size k to efficiently keep track of the k largest numbers. This way, the smallest element in the heap is always the k-th largest overall, and we avoid unnecessary sorting of all elements.
Approach
- Create a min heap (priority queue) with a custom comparator for string numbers (compare by length, then lexicographically).
- Iterate through each string in nums:
- Add the string to the heap.
- If the heap size exceeds k, remove the smallest element.
- After all elements are processed, the top of the heap is the k-th largest number.
Code
Java
public String kthLargestNumber(String[] nums, int k) {
PriorityQueue<String> minHeap = new PriorityQueue<>((o1, o2) -> {
if (o1.length() == o2.length()) { // If the same length then compare by their string
return o1.compareTo(o2);
}
return Integer.compare(o1.length(), o2.length()); // Compare by their length
});
for (String num : nums) {
minHeap.offer(num);
if (minHeap.size() > k) {
minHeap.poll(); // pop the minimum value in the heap
}
}
return minHeap.poll();
}
Complexity
- ⏰ Time complexity:
O(n * m * log k), where n is the number of strings, m is the average string length, and k is the heap size. Each insertion and removal in the heap takes O(log k), and string comparison takes O(m). - 🧺 Space complexity:
O(k * m), as the heap stores up to k strings, each of length up to m.
Method 3 – Using Max Heap
Intuition
By using a max heap, we can efficiently extract the k-th largest number by repeatedly removing the largest elements. This approach leverages the heap property to always access the largest element in constant time.
Approach
- Create a max heap (priority queue) with a custom comparator for string numbers (compare by length, then lexicographically).
- Add all strings from nums to the max heap.
- Remove the largest element from the heap k-1 times.
- The next element removed is the k-th largest number.
Code
Java
String kthLargestNumberHeap(String[] nums, int k) {
PriorityQueue<String> maxHeap = new PriorityQueue<>((a, b) -> {
if (b.length() != a.length()) return b.length() - a.length();
return b.compareTo(a);
});
for (String s : nums) {
maxHeap.add(s);
}
while (k > 1) {
maxHeap.poll();
k--;
}
return maxHeap.poll();
}
Complexity
- ⏰ Time complexity:
O(n * m + k * log n), where n is the number of strings, m is the average string length. Building the heap takes O(n * m), and each removal takes O(log n). - 🧺 Space complexity:
O(n * m), as the heap stores all n strings, each of length up to m.
Method 4 – Quickselect
Intuition
Quickselect is an efficient selection algorithm to find the k-th largest element without fully sorting the array. It partitions the array around a pivot, narrowing down the search space to the relevant part.
Approach
- Shuffle the array to avoid worst-case performance.
- Use partitioning to place the k-th largest element in its correct position.
- Recursively partition the relevant subarray until the k-th largest is found.
- Use a custom comparator for string numbers (compare by length, then lexicographically).
Code
Java
public String kthLargestNumber(String[] nums, int K) {
shuffle(nums);
K--;
int len = nums.length, l = 0, r = len - 1;
int mid = 0;
while (l <= r) {
mid = partition(nums, l, r);
if (mid == K) break;
if (mid < K) {
l = mid + 1;
} else {
r = mid - 1;
}
}
return nums[K];
}
private int partition(String[] nums, int l, int r) {
String pivot = nums[l];
while (l < r) {
while (l < r && compare(nums[r], pivot) >= 0) r--;
nums[l] = nums[r];
while (l < r && compare(nums[l], pivot) <= 0) l++;
nums[r] = nums[l];
}
nums[l] = pivot;
return l;
}
private int compare(String p1, String p2) {
return p1.length() == p2.length() ? p2.compareTo(p1) : Integer.compare(p2.length(), p1.length());
}
private void shuffle(String a[]) {
Random random = new Random();
for(int ind = 1; ind < a.length; ind++) {
final int r = random.nextInt(ind + 1);
exch(a, ind, r);
}
}
private void exch(String[] a, int i, int j) {
final String tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
Complexity
- ⏰ Time complexity:
O(n * m)on average, where n is the number of strings and m is the average string length. Partitioning and comparisons are linear in n, and each comparison is O(m). - 🧺 Space complexity:
O(1)additional space, as partitioning is done in-place.