Find the Kth Largest Integer in the Array
kth-largest where elements are strings of arbitrary length — custom comparator on length then lex.
5 min read
top-k heaps
Problem#
Given nums of strings representing non-negative integers (no leading zeros), return the kth largest as a string.
Examples#
nums = ["3","6","7","10"], k = 4→"3"nums = ["2","21","12","1"], k = 3→"2"
Constraints#
1 <= nums.length <= 10^4, lengths up to100.
Approach#
Compare strings numerically without converting to int (they may overflow): longer length wins; equal length, lex order. Use a min-heap of size k.
Solution#
class Solution {public: string kthLargestNumber(vector<string>& nums, int k) { auto cmp = [](const string& a, const string& b) { if (a.size() != b.size()) return a.size() > b.size(); // greater means lower priority in min-heap return a > b; }; priority_queue<string, vector<string>, decltype(cmp)> pq(cmp); for (auto& s : nums) { pq.push(s); if ((int)pq.size() > k) pq.pop(); } return pq.top(); }};import "container/heap"
// numericLess: returns true if a < b in numeric order (shorter wins; equal length → lex).func numericLess(a, b string) bool { if len(a) != len(b) { return len(a) < len(b) } return a < b}
type strHeap []string
func (h strHeap) Len() int { return len(h) }func (h strHeap) Less(i, j int) bool { return numericLess(h[i], h[j]) }func (h strHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }func (h *strHeap) Push(x interface{}) { *h = append(*h, x.(string)) }func (h *strHeap) Pop() interface{} { old := *h; n := len(old); x := old[n-1]; *h = old[:n-1]; return x }
func kthLargestNumber(nums []string, k int) string { pq := &strHeap{} for _, s := range nums { heap.Push(pq, s) if pq.Len() > k { heap.Pop(pq) } } return (*pq)[0]}import heapqfrom typing import List
class Solution: def kthLargestNumber(self, nums: List[str], k: int) -> str: # Min-heap of size k keyed by (length, value) — numeric order on numeric strings. heap: List[tuple] = [] for s in nums: key = (len(s), s) if len(heap) < k: heapq.heappush(heap, (key, s)) elif key > heap[0][0]: heapq.heapreplace(heap, (key, s)) return heap[0][1]// numericLess: returns true if a < b in numeric order (shorter wins; equal length → lex)const numericLess = (a, b) => { if (a.length !== b.length) return a.length < b.length; return a < b;};
class MinHeap { constructor() { this.h = []; } size() { return this.h.length; } peek() { return this.h[0]; } push(v) { this.h.push(v); let i = this.h.length - 1; while (i > 0) { const p = (i - 1) >> 1; if (!numericLess(this.h[i], this.h[p])) break; [this.h[p], this.h[i]] = [this.h[i], this.h[p]]; i = p; } } pop() { const top = this.h[0]; const last = this.h.pop(); if (this.h.length) { this.h[0] = last; let i = 0, n = this.h.length; while (true) { const l = 2 * i + 1, r = 2 * i + 2; let s = i; if (l < n && numericLess(this.h[l], this.h[s])) s = l; if (r < n && numericLess(this.h[r], this.h[s])) s = r; if (s === i) break; [this.h[s], this.h[i]] = [this.h[i], this.h[s]]; i = s; } } return top; }}
var kthLargestNumber = function(nums, k) { const pq = new MinHeap(); for (const s of nums) { pq.push(s); if (pq.size() > k) pq.pop(); } return pq.peek();};class Solution { public String kthLargestNumber(String[] nums, int k) { PriorityQueue<String> pq = new PriorityQueue<>((a, b) -> { if (a.length() != b.length()) return Integer.compare(a.length(), b.length()); return a.compareTo(b); }); for (String s : nums) { pq.offer(s); if (pq.size() > k) pq.poll(); } return pq.peek(); }}// numericLess: returns true if a < b in numeric order (shorter wins; equal length → lex)const numericLess = (a: string, b: string): boolean => { if (a.length !== b.length) return a.length < b.length; return a < b;};
class MinHeap { private h: string[] = []; size(): number { return this.h.length; } peek(): string { return this.h[0]; } push(v: string): void { this.h.push(v); let i = this.h.length - 1; while (i > 0) { const p = (i - 1) >> 1; if (!numericLess(this.h[i], this.h[p])) break; [this.h[p], this.h[i]] = [this.h[i], this.h[p]]; i = p; } } pop(): string { const top = this.h[0]; const last = this.h.pop()!; if (this.h.length) { this.h[0] = last; let i = 0; const n = this.h.length; while (true) { const l = 2 * i + 1, r = 2 * i + 2; let s = i; if (l < n && numericLess(this.h[l], this.h[s])) s = l; if (r < n && numericLess(this.h[r], this.h[s])) s = r; if (s === i) break; [this.h[s], this.h[i]] = [this.h[i], this.h[s]]; i = s; } } return top; }}
function kthLargestNumber(nums: string[], k: number): string { const pq = new MinHeap(); for (const s of nums) { pq.push(s); if (pq.size() > k) pq.pop(); } return pq.peek();}Editorial#
Lengths up to 100 mean stoll doesn’t suffice — strings encode arbitrarily large integers. The “longer-first” numeric ordering is a primitive worth memorizing: equal length means equal digit count, so lex order coincides with numeric order.
Complexity#
- Time: O(n log k * L) where L is string length.
- Space: O(k * L).
Concept revision#
Related#