给你一个整数 n
,请你在无限的整数序列 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ...]
中找出并返回第 n
位上的数字。
示例 1:
1
2
3输入:n = 3 输出:3
示例 2:
1
2
3
4输入:n = 11 输出:0 解释:第 11 位数字在序列 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ... 里是 0 ,它是 10 的一部分。
提示:
- 1 <= n <= 231 - 1
- 第
n
位上的数字是按计数单位(digit)从前往后数的第n
个数,参见 示例 2 。
解题思路
为了得到无限整数序列中的第 n 位数字,需要知道第 n 位数字是哪一个整数的第几位。如果知道第 n 位数字所在整数是几位数,就能计算得到第 n 位数字是哪一个整数的第几位。
假设第 n 位数字所在整数是 d 位数,则所有位数不超过 d - 1 的整数的位数之和小于 n,且所有位数不超过 d 的整数的位数之和大于等于 n。由于所有位数不超过 x 的整数的位数之和关于 x 单调递增,因此可以使用二分查找确定上述 d 的值。对于某个 x,如果所有位数不超过 x 的整数的位数之和小于 n,则 d > x,否则 d <= x,以此调整二分查找的上下界。
由于任何整数都至少是一位数,因此 d 的最小值是 1。对于 d 的上界,可以通过找规律的方式确定。
- 1 位数的范围是 1 到 9,共有 9 个数,所有 1 位数的位数之和是 1 * 9 = 9。
- 2 位数的取值范围是 10 到 99,共有 90 个数,所有 2 位数的位数之和是 2 * 90 = 180。
- 3 位数的取值范围是 100 到 999,共有 900 个数,所有 3 位数的位数之和是 3 × 900 = 2700。
- ……
推广到一般情形,x 位数的范围是 10^x - 1^ 到 10x - 1,共有 10x - 1 - 10^x - 1^ + 1 = 9 * 10^x - 1^ 个数,所有 x 位数的位数之和是 x * 9 * 10^x - 1^ 。
由于 n 的最大值为 231 - 1 ,约为 2 * 109 ,当 x = 9 时,x * 9 * 10^x - 1^ = 8.1 * 109 > 231 - 1 ,因此第 n 位数字所在整数最多是 9 位数,令 d 的上界为 9 即可。
在得到 d 的值之后,可以根据上述规律计算得到所有位数不超过 d - 1 的整数的位数之和,然后得到第 n 位数在所有 d 位数的序列中的下标,为了方便计算,将下标转换成从 0 开始记数。具体而言,用 prevDigits 表示所有位数不超过 d - 1 的整数的位数之和,则第 n 位数在所有 d 位数的序列中的下标是 index = n - prevDigits - 1,index 的最小可能取值是 0。
得到下标 index 之后,可以得到无限整数序列中的第 n 位数字是第 ⌊ index / d ⌋ 个 d 位数的第 index mod d 位,注意编号都从 0 开始。
由于最小的 d 位数是 10^d - 1^ ,因此第 n 位数字所在的整数是 10^d - 1^ +⌊index / d⌋,该整数的右边第 d - (index mod d) - 1 位(计数从 0 开始)即为无限整数序列中的第 n 位数字。
代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32// 400. 第 N 位数字 func findNthDigit(_ n: Int) -> Int { func totalDigits(_ length: Int) -> Int { var digits = 0, curLength = 1, curCount = 9 while curLength <= length { digits += curLength * curCount curLength += 1 curCount *= 10 } return digits } var low = 1, high = 9 while low < high { let mid = (high - low) / 2 + low if totalDigits(mid) < n { low = mid + 1 } else { high = mid } } let d = low let prevDigits = totalDigits(d - 1) let index = n - prevDigits - 1 let start = Int(pow(10.0, Double(d - 1))) let num = start + index / d let digitIndex = index % d let digit = (num / Int(pow(10.0, Double(d - digitIndex - 1)))) % 10 return digit }
最后
以上就是复杂指甲油最近收集整理的关于iOS LeetCode ☞ 第 N 为数字的全部内容,更多相关iOS内容请搜索靠谱客的其他文章。
发表评论 取消回复