解题思路
关键思路:
- 字典序排列的特点:
- 按照字符串比较的方式排序(如:1, 10, 11, 2, 3, ...)
- 对于前缀相同的数字,较短的数字排在前面
- 解题方法:
- 不能实际生成所有数字( 可达 )
- 通过计算每个前缀下的数字个数来定位
- 逐步构建目标数字
代码
#include <iostream>
using namespace std;
class Solution {
public:
// 计算[1,n]范围内以prefix为前缀的数字个数
long long countNumbers(long long prefix, long long n) {
long long current = prefix;
long long next = prefix + 1;
long long count = 0;
while (current <= n) {
count += min(next, n + 1) - current;
current *= 10;
next *= 10;
}
return count;
}
long long findKthNumber(long long n, long long m) {
long long current = 1; // 从1开始查找
m--; // 因为从1开始,所以m需要减1
while (m > 0) {
long long step = countNumbers(current, n);
if (step <= m) {
m -= step;
current++;
} else {
m--;
current *= 10;
}
}
return current;
}
};
int main() {
long long n, m;
cin >> n >> m;
Solution solution;
cout << solution.findKthNumber(n, m) << endl;
return 0;
}
import java.util.*;
public class Main {
static class Solution {
// 计算[1,n]范围内以prefix为前缀的数字个数
public long countNumbers(long prefix, long n) {
long current = prefix;
long next = prefix + 1;
long count = 0;
while (current <= n) {
count += Math.min(next, n + 1) - current;
current *= 10;
next *= 10;
}
return count;
}
public long findKthNumber(long n, long m) {
long current = 1; // 从1开始查找
m--; // 因为从1开始,所以m需要减1
while (m > 0) {
long step = countNumbers(current, n);
if (step <= m) {
m -= step;
current++;
} else {
m--;
current *= 10;
}
}
return current;
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
long n = sc.nextLong();
long m = sc.nextLong();
Solution solution = new Solution();
System.out.println(solution.findKthNumber(n, m));
}
}
def count_numbers(prefix: int, n: int) -> int:
"""计算[1,n]范围内以prefix为前缀的数字个数"""
current = prefix
next_prefix = prefix + 1
count = 0
while current <= n:
count += min(next_prefix, n + 1) - current
current *= 10
next_prefix *= 10
return count
def find_kth_number(n: int, m: int) -> int:
"""找到字典序第m小的数"""
current = 1 # 从1开始查找
m -= 1 # 因为我们从1开始,所以m需要减1
while m > 0:
step = count_numbers(current, n)
if step <= m:
m -= step
current += 1
else:
m -= 1
current *= 10
return current
if __name__ == "__main__":
n, m = map(int, input().split())
print(find_kth_number(n, m))
算法及复杂度
- 算法:字典序遍历 + 数位统计
- 时间复杂度:,每次需要计算前缀下的数字个数
- 空间复杂度:,只使用常数额外空间