DEV Community

Cover image for ๐ŸŒ Beginner-Friendly Guide to Solving "K-th Smallest in Lexicographical Order" LeetCode 440 (C++ | JavaScript | Python)
Om Shree
Om Shree

Posted on

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

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. ๐ŸŒ๐Ÿ”ข

Top comments (2)

Collapse
 
thedeepseeker profile image
Anna kowoski

well explained, was waiting for your article.

Collapse
 
om_shree_0709 profile image
Om Shree

Haha, Thank you Anna.

Some comments may only be visible to logged-in visitors. Sign in to view all comments.