LeetCode 400 第 N 位数字


文章目录

摘要

这道题让你在无限整数序列 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ... 里,把每个数按顺序拼成一条长长的数字串,然后返回第 n 位上的那个数字(0~9)。比如 n=3 就是第 3 个字符,即 "3";n=11 时,序列是 "1234567891011...",第 11 位是 10 里的那个 "0"。暴力做法是逐个数字拼字符串再数到第 n 位,n 最大到 2^31-1 会超时,所以要用「按位数分段」:先算出一位数、两位数、三位数......各占多少位,确定第 n 位落在哪一段、对应哪个数、以及是该数的第几位,最后取出那一位数字即可。下面用 Swift 实现并说明分段和取位的细节。

描述

给你一个整数 n,请你在无限整数序列 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ... 中找出并返回第 n 位上的数字。这里「第 n 位」指的是把序列里每个数依次拼成一个大串后,从左到右数第 n 个字符(从 1 开始计数),该字符一定是 0~9 中的某一个。

示例 1:

复制代码
输入:n = 3
输出:3
解释:序列拼成 "123456789...",第 3 位是 "3"。

示例 2:

复制代码
输入:n = 11
输出:0
解释:序列为 1,2,3,4,5,6,7,8,9,10,11,...,拼成 "1234567891011...",第 11 位数字是 10 里的 "0"。

提示:

  • 1 <= n <= 2^31 - 1

核心思路:按「数字的位数」分段。一位数 1~9 共 9 个数、占 9 位;两位数 10~99 共 90 个、占 180 位;三位数 100~999 共 900 个、占 2700 位......先确定第 n 位落在哪一段,再算出是这一段里的第几个数、以及是该数的第几位,最后从该数中取出对应位返回。

题解答案

swift 复制代码
class Solution400 {
    func findNthDigit(_ n: Int) -> Int {
        var n = n
        var width = 1
        var base = 1
        var count = 9

        while n > count {
            n -= count
            width += 1
            base *= 10
            count = 9 * base * width
        }

        let numIndex = (n - 1) / width
        let digitIndex = (n - 1) % width
        let number = base + numIndex
        let s = String(number)
        let index = s.index(s.startIndex, offsetBy: digitIndex)
        return Int(String(s[index]))!
    }
}

题解代码分析

为什么要按位数分段

序列可以看成:先写所有一位数(1~9),再写所有两位数(10~99),再写三位数(100~999)......每一段里,数的个数和每个数的位数都是固定的。一位数有 9 个,每个 1 位,共 9 位;两位数有 90 个,每个 2 位,共 180 位;三位数有 900 个,每个 3 位,共 2700 位。一般地,位数为 width 的那一段,最小的数是 10^(width-1)(即代码里的 base),个数是 9 * base,总位数是 9 * base * width。用 n 不断减去当前段的总位数,减不动时,第 n 位就落在当前这一段里,这样就不用真的去拼字符串,也能在 O(位数) 内定位到「第几个数、第几位」。

循环在做什么

一开始 width = 1base = 1count = 9,表示「一位数这一段一共有 9 位」。只要 n > count,说明第 n 位还在后面,就减去这 9 位,然后进入二位数:width = 2base = 10count = 9 * 10 * 2 = 180。再若 n 还大于 180,再减、再进三位数......直到某一段的 count 不小于当前的 n,此时 n 已经变成「在当前这一段内,从 1 开始数的第几位」。

如何算出是哪个数、第几位

当前段里,每个数占 width 位,所以「第 n 位」对应的是这一段里第 (n-1)/width 个数(从 0 开始数),且是该数的第 (n-1)%width 位(从左往右、从 0 开始)。这一段最小的数是 base,所以目标数 number = base + (n-1)/width。然后把 number 转成字符串,取下标为 (n-1)%width 的字符,转成数字返回即可。用字符串取位可以避免手写「求某数从左数第 k 位」的除法和取模,代码更直观、也不容易搞错进制。

示例 n=3 的过程

一开始 width=1,base=1,count=9。n=3 不大于 9,不进入循环。numIndex=(3-1)/1=2,digitIndex=(3-1)%1=0,number=1+2=3,即第 3 位落在数字 3 上,且是 3 的第 0 位(即最高位),也就是 "3",返回 3。

示例 n=11 的过程

width=1,count=9,n=11>9,n 减 9 变成 2,width=2,base=10,count=180。n=2 不大于 180,退出循环。numIndex=(2-1)/2=0,digitIndex=(2-1)%2=1,number=10+0=10,即第 11 位落在数字 10 上,且是 10 的第 1 位(从左数第二位),即 "0",返回 0。

示例测试及结果

示例 1:n = 3

序列前缀为 "123456789...",第 3 位是数字 3 本身,输出 3

示例 2:n = 11

一位数占前 9 位,第 10、11 位来自 10,即 "1" 和 "0",第 11 位为 0

示例 3:n = 1 或 n = 9

第 1 位是 "1",第 9 位是 "9",均在一位数段内,输出 1 和 9。

示例 4:刚好跨段

n=10 时,第 10 位是 10 的十位 "1";n=12 时是 11 的个位 "1"。用上述公式可验证 numIndex、digitIndex 与 number 均正确。

示例 5:较大的 n(多位数段)

例如 n 落在三位数、四位数段时,逻辑相同:先减掉所有更短段的总位数,再在当前段内用 (n-1)/width 和 (n-1)%width 定位到具体数字和位,取字符转成数字返回。

时间复杂度

循环次数等于「第 n 位所在数字的位数」,即 O(log n) 级别(因为位数约为 log₁₀(n))。循环内只有常数次加减乘除和赋值。定位到 number 后,转字符串和按下标取字符也是 O(位数),即 O(log n)。整体 O(log n)

空间复杂度

只用了若干 Int 变量和一次 String(number),字符串长度等于当前数的位数,即 O(log n)。没有递归、没有和 n 同规模的数组,空间 O(log n)

与实际场景的结合

这类「在无限序列里按位置取元素」的问题,在编码、索引、分页里会碰到。比如把一串连续 ID 或编号看成序列,问「第 k 个编码单元对应哪一段、哪一位」;或者在某些压缩、编码方案里,需要在不展开全文的情况下定位到第 n 个符号。掌握「按段计数 + 段内偏移」的思路,就可以在不真正构造整条序列的前提下 O(log n) 回答单次查询,适合 n 很大的情况。

总结

LeetCode 400 第 N 位数字的做法是:把序列按数字位数分成多段(一位、两位、三位......),先根据 n 确定第 n 位落在哪一段,再在该段内用 (n-1)/width 得到是第几个数、用 (n-1)%width 得到是该数的第几位,算出目标数字后转成字符串取对应位字符即可得到 0~9 的答案。时间 O(log n),空间 O(log n),无需真正拼接整条序列即可处理 n 最大到 2^31-1 的规模。

相关推荐
江畔柳前堤6 小时前
大语言模型分布式训练:从并行策略到万卡工程的系统梳理
人工智能·分布式·深度学习·算法·目标检测·机器学习·语言模型
Forever Nore7 小时前
LeetCode 4 寻找两个正序数组的中位数 - 二分
算法·leetcode
罗西的思考8 小时前
【OpenClaw具身硬件】MiniClaw 阅读笔记---(1)基础
人工智能·算法·机器学习
蛋先生DX9 小时前
大模型参数存储格式揭秘:BF不是男朋友
深度学习·算法·llm
爱跳舞的烤冷面10 小时前
自学嵌入式第22天(数据结构——哈希)
数据结构·算法·哈希算法
猎嘤一号10 小时前
博弈论(Game Theory)的理论、算法与工程
人工智能·算法·安全·博弈论
月光船幽幽10 小时前
影子模式下保护 logits 不被修改
人工智能·python·算法
马拉AI10 小时前
腾讯开源 Agent 记忆系统,AI“换对话就忘”的问题有了新解法(附安装使用教程)
人工智能·算法·开源·科研
地平线开发者12 小时前
征程6工具链模型X86推理方式说明
算法
地平线开发者12 小时前
【征程6】校准量化中HistogramObserver解析
算法