🧠
Optimized Binary Search with Early Break in Counting
💡 This approach improves the counting function by breaking early when counts exceed k, saving time in practice. It is a practical optimization of approach 2.
Intuition
While counting how many numbers are ≤ mid, stop counting once count exceeds k since we only need to know if count < k or not.
Algorithm
- Set low = 1 and high = m * n.
- While low < high:
- Compute mid = (low + high) // 2.
- Count numbers ≤ mid with early break if count > k.
- If count < k, set low = mid + 1; else set high = mid.
- Return low.
💡 Early break avoids unnecessary counting once we know mid is too small.
def findKthNumber(m, n, k):
def countLessEqual(x):
count = 0
for i in range(1, m+1):
count += min(n, x // i)
if count >= k:
break
return count
low, high = 1, m * n
while low < high:
mid = (low + high) // 2
if countLessEqual(mid) < k:
low = mid + 1
else:
high = mid
return low
# Driver code
if __name__ == '__main__':
print(findKthNumber(3, 3, 5)) # Output: 3
Line Notes
def countLessEqual(x):Counting function with early break
for i in range(1, m+1):Iterate rows
count += min(n, x // i)Add count for row i
if count >= k:Stop early if count already enough
breakBreak loop to save time
low, high = 1, m * nInitialize binary search range
while low < high:Binary search loop
mid = (low + high) // 2Calculate mid
if countLessEqual(mid) < k:Check if mid too small
low = mid + 1Increase low if needed
else: high = midDecrease high otherwise
public class Solution {
public static int findKthNumber(int m, int n, int k) {
int low = 1, high = m * n;
while (low < high) {
int mid = low + (high - low) / 2;
if (countLessEqual(m, n, mid, k) < k) {
low = mid + 1;
} else {
high = mid;
}
}
return low;
}
private static int countLessEqual(int m, int n, int x, int k) {
int count = 0;
for (int i = 1; i <= m; i++) {
count += Math.min(n, x / i);
if (count >= k) {
break;
}
}
return count;
}
public static void main(String[] args) {
System.out.println(findKthNumber(3, 3, 5)); // Output: 3
}
}
Line Notes
int low = 1, high = m * n;Initialize binary search range
while (low < high)Binary search loop
int mid = low + (high - low) / 2;Calculate mid safely
if (countLessEqual(m, n, mid, k) < k)Check if mid too small
low = mid + 1;Increase low if count less than k
else { high = mid; }Decrease high otherwise
for (int i = 1; i <= m; i++)Count numbers row-wise
count += Math.min(n, x / i);Add count for row i
if (count >= k) { break; }Early break to save time
#include <iostream>
#include <algorithm>
using namespace std;
int countLessEqual(int m, int n, int x, int k) {
int count = 0;
for (int i = 1; i <= m; i++) {
count += min(n, x / i);
if (count >= k) break;
}
return count;
}
int findKthNumber(int m, int n, int k) {
int low = 1, high = m * n;
while (low < high) {
int mid = low + (high - low) / 2;
if (countLessEqual(m, n, mid, k) < k) {
low = mid + 1;
} else {
high = mid;
}
}
return low;
}
int main() {
cout << findKthNumber(3, 3, 5) << endl; // Output: 3
return 0;
}
Line Notes
int countLessEqual(int m, int n, int x, int k)Counting with early break
for (int i = 1; i <= m; i++)Iterate rows
count += min(n, x / i);Add count for row i
if (count >= k) break;Stop counting early if enough
int low = 1, high = m * n;Initialize binary search range
while (low < high)Binary search loop
int mid = low + (high - low) / 2;Calculate mid
if (countLessEqual(m, n, mid, k) < k)Check if mid too small
low = mid + 1;Increase low if needed
else { high = mid; }Decrease high otherwise
function findKthNumber(m, n, k) {
function countLessEqual(x) {
let count = 0;
for (let i = 1; i <= m; i++) {
count += Math.min(n, Math.floor(x / i));
if (count >= k) break;
}
return count;
}
let low = 1, high = m * n;
while (low < high) {
let mid = Math.floor((low + high) / 2);
if (countLessEqual(mid) < k) {
low = mid + 1;
} else {
high = mid;
}
}
return low;
}
// Test
console.log(findKthNumber(3, 3, 5)); // Output: 3
Line Notes
function countLessEqual(x)Counting function with early break
for (let i = 1; i <= m; i++)Iterate rows
count += Math.min(n, Math.floor(x / i));Add count for row i
if (count >= k) break;Stop counting early if enough
let low = 1, high = m * n;Initialize binary search range
while (low < high)Binary search loop
let mid = Math.floor((low + high) / 2);Calculate mid
if (countLessEqual(mid) < k)Check if mid too small
low = mid + 1;Increase low if needed
else { high = mid; }Decrease high otherwise
TimeO(m * log(m * n)) with early break optimization
SpaceO(1)
Early break reduces average counting time, improving practical runtime though worst-case remains same.
💡 This optimization helps especially when k is small, avoiding full row scans.
Interview Verdict: Accepted
This is a practical improvement over approach 2, often used in interviews to show attention to efficiency.