🌍 Beginner-Friendly Guide to Solving "K-th Smallest in Lexicographical Order" LeetCode 440 (C++ | JavaScript | Python)
Om Shree

Om Shree @om_shree_0709

About: 🚀 Front-End Developer | UI/UX Enthusiast | EdTech Innovator I specialize in HTML5, CSS3, and JavaScript (ES6+), leveraging React.js ⚛️ and Tailwind CSS 🎨 to build scalable, high-performance web app

Location:
India
Joined:
Feb 27, 2025

🌍 Beginner-Friendly Guide to Solving "K-th Smallest in Lexicographical Order" LeetCode 440 (C++ | JavaScript | Python)

Publish Date: Jun 9
13 3

Hey coding pioneers! 🧭
Today, we’re tackling a Hard problem that blends greedy algorithms with lexicographical tree traversal — a neat and elegant concept hiding behind a deceptively simple prompt.

Let’s dive into LeetCode 440: K-th Smallest in Lexicographical Order — and we’ll break it down in a clean, beginner-friendly way. 💡


📜 Problem Overview

Given two integers n and k, return the k-th smallest number in lexicographical (dictionary) order from the range [1, n].

🧾 Example 1:

Input: n = 13, k = 2  
Output: 10
Explanation: Lexicographical order → [1,10,11,12,13,2,3,4,5,6,7,8,9]
Enter fullscreen mode Exit fullscreen mode

🧾 Example 2:

Input: n = 1, k = 1  
Output: 1
Enter fullscreen mode Exit fullscreen mode

🧠 Intuition & Strategy

This problem can be visualized as a 10-ary tree (prefix tree) rooted at 1, where each node represents a number and each child adds another digit to it.

Think of lexicographical order as a preorder traversal of this virtual tree:

  • 1 → 10 → 100...
  • Then backtrack and go to 2 → 20 → 200..., and so on.

Our goal is to traverse this tree until we reach the k-th node.

🔍 Key Insight:

We don’t need to generate the entire order. Instead, we count how many nodes (i.e., numbers) are between a prefix a and its sibling prefix b = a + 1.

This count is called a “gap”, and we use it to decide whether to:

  • Move to the next sibling (increment a)
  • Go deeper in the subtree (multiply a by 10)

📘 getGap(a, b, n)

This helper function calculates how many numbers exist in the range [a, b) under the lexicographical tree and up to n.

E.g., getGap(1, 2, 13) returns how many numbers lie between 1 and 2:
=> [1, 10, 11, 12, 13] => 5
Enter fullscreen mode Exit fullscreen mode

⚙️ C++ Code (Efficient)

class Solution {
 public:
  int findKthNumber(int n, int k) {
    long ans = 1;

    for (int i = 1; i < k;) {
      const long gap = getGap(ans, ans + 1, n);
      if (i + gap <= k) {
        i += gap;
        ++ans;
      } else {
        ++i;
        ans *= 10;
      }
    }

    return ans;
  }

 private:
  long getGap(long a, long b, long n) {
    long gap = 0;
    while (a <= n) {
      gap += min(n + 1, b) - a;
      a *= 10;
      b *= 10;
    }
    return gap;
  }
};
Enter fullscreen mode Exit fullscreen mode

🌐 JavaScript Version

var findKthNumber = function(n, k) {
    let curr = 1;
    let i = 1;

    const getGap = (a, b, n) => {
        let gap = 0;
        while (a <= n) {
            gap += Math.min(n + 1, b) - a;
            a *= 10;
            b *= 10;
        }
        return gap;
    };

    while (i < k) {
        let gap = getGap(curr, curr + 1, n);
        if (i + gap <= k) {
            i += gap;
            curr++;
        } else {
            i++;
            curr *= 10;
        }
    }

    return curr;
};
Enter fullscreen mode Exit fullscreen mode

🐍 Python Version

class Solution:
    def findKthNumber(self, n: int, k: int) -> int:
        def getGap(a: int, b: int, n: int) -> int:
            gap = 0
            while a <= n:
                gap += min(n + 1, b) - a
                a *= 10
                b *= 10
            return gap

        curr = 1
        i = 1

        while i < k:
            gap = getGap(curr, curr + 1, n)
            if i + gap <= k:
                i += gap
                curr += 1
            else:
                i += 1
                curr *= 10

        return curr
Enter fullscreen mode Exit fullscreen mode

🧪 Test Case Scenarios

Input: n = 13, k = 2  
Output: 10  
→ Lexicographical: [1,10,11,12,13,2,3...]

Input: n = 100, k = 10  
Output: 17  
→ We skip prefixes based on calculated gaps.

Input: n = 1000000, k = 1000  
Output: Efficient tree traversal returns result in milliseconds.

Input: n = 1, k = 1  
Output: 1  
→ Base case
Enter fullscreen mode Exit fullscreen mode

🧮 Time & Space Complexity

Time Complexity: O(log n * log n)
- log n levels in the tree
- Each getGap call takes O(log n) time

Space Complexity: O(1)
- Constant extra space (no recursion or data structures)
Enter fullscreen mode Exit fullscreen mode

✨ Wrap Up

This problem shines in combining greedy algorithms, prefix trees, and mathematical counting — all without recursion or brute force. 🚀

✅ It’s a perfect example of using structured exploration to cut down unnecessary computation.

If you learned something new today, consider following for more in-depth problem breakdowns and sharing this with your fellow devs! 👨‍💻👩‍💻

Keep building, keep exploring. 🌍🔢

Comments 3 total

Add comment