Advertisement

K-th Smallest in Lexicographical Order - LeetCode 440 Solution

K-th Smallest in Lexicographical Order - Complete Solution Guide

K-th Smallest in Lexicographical Order is LeetCode problem 440, a Hard level challenge. This complete guide provides step-by-step explanations, multiple solution approaches, and optimized code in python3, java, cpp, c.

Problem Statement

Given two integers n and k , return the k th lexicographically smallest integer in the range [1, n] . Example 1: Input: n = 13, k = 2 Output: 10 Explanation: The lexicographical order is [1, 10, 11, 12, 13, 2, 3, 4, 5, 6, 7, 8, 9], so the second smallest number is 10. Example 2: Input: n = 1, k = 1 Output: 1 Constraints: 1 <= k <= n <= 10 9

Detailed Explanation

The problem asks us to find the k-th smallest integer in lexicographical order among the integers from 1 to n. Lexicographical order is similar to alphabetical order but for numbers. For example, if n = 13 and k = 2, the lexicographical order is [1, 10, 11, 12, 13, 2, 3, 4, 5, 6, 7, 8, 9], and the 2nd smallest number is 10. The constraints specify that 1 <= k <= n <= 10^9.

Solution Approach

The solution uses a depth-first traversal approach on a conceptual lexicographical tree. The root of the tree is '1', and each node's children are formed by appending digits 0-9 to it. The algorithm starts with the current number 'curr' initialized to 1 and reduces k until it reaches 0. In each iteration, it calculates the number of integers between 'curr' and 'curr + 1' which are also less than or equal to 'n' using the `count_steps` function. If the number of integers 'steps' is less than or equal to the current value of 'k', it means the k-th smallest integer is not in the subtree rooted at 'curr', so we increment 'curr' by 1 and reduce 'k' by 'steps'. Otherwise, it means the k-th smallest integer is in the subtree rooted at 'curr', so we move deeper into the tree by multiplying 'curr' by 10 and reduce 'k' by 1.

Step-by-Step Algorithm

  1. Step 1: Initialize 'curr' to 1 and decrement 'k' by 1. The reason for decrementing k by one initially is to convert it to a zero-based index, making calculations easier during traversal.
  2. Step 2: While 'k' is greater than 0, calculate the number of steps between 'curr' and 'curr + 1' which are less than or equal to 'n' using the `count_steps` function.
  3. Step 3: If 'steps' is less than or equal to 'k', subtract 'steps' from 'k' and increment 'curr' by 1. This means the k-th smallest number is not in the subtree of 'curr' and we advance to the next sibling.
  4. Step 4: Otherwise, if 'steps' is greater than 'k', subtract 1 from 'k' and multiply 'curr' by 10. This means the k-th smallest number is in the subtree of 'curr' and we go down one level in the lexicographical tree.
  5. Step 5: Repeat steps 2-4 until 'k' is equal to 0. At this point, 'curr' will be the k-th smallest number.

Key Insights

  • Insight 1: The key is to realize that we don't need to generate all numbers from 1 to n and sort them. Instead, we can traverse the lexicographical tree and count how many numbers fall under each prefix.
  • Insight 2: The count_steps function is crucial. It determines how many numbers are lexicographically between 'curr' and 'curr + 1' while being less than or equal to 'n'. This helps determine if we should move deeper into the tree (multiply by 10) or move to the next sibling (increment by 1).
  • Insight 3: It's important to use long data types (in C++ and C) or be mindful of potential integer overflow when calculating steps, especially with the multiplication and addition operations.

Complexity Analysis

Time Complexity: O(log(n)*log(n))

Space Complexity: O(1)

Topics

This problem involves: Trie.

Companies

Asked at: DE Shaw, Hulu, Samsung.