生成仅含数字1、2、3的序列并求解第10^18项的技术咨询
解决由1、2、3组成的序列第10¹⁸项的问题
嘿,这个问题完全不用暴力生成前10¹⁸项——咱们先拆解序列规律,用数学方法直接算出结果,效率拉满!
首先明确这个序列的排列逻辑:
- 1位数字:
1、2、3,共3项(3¹个) - 2位数字:按字典序排列所有由1、2、3组成的两位数,即
11、12、13、21、22、23、31、32、33,共9项(3²个) - 3位数字:同理,按字典序排列所有3位组合,共27项(3³个)
- ...以此类推,n位数字的项数是3ⁿ,整个序列按数字长度从小到大排列,同长度内按字典序(字符串排序)排列。
步骤1:确定目标项所在的数字长度
先计算前k位数字的总项数,这是等比数列求和:总项数S(k) = 3¹ + 3² + ... + 3ᵏ = (3^(k+1) - 3) / 2
我们要找到最小的n,使得S(n-1) < 10¹⁸ ≤ S(n),也就是目标项落在n位数字的分组里。
通过估算和验证:
3³⁸ ≈ 1.35e18,所以S(37) = (3³⁸ - 3)/2 ≈ 6.75e17(小于1e18)S(38) = (3³⁹ - 3)/2 ≈ 2.025e18(大于1e18)
因此,目标项在38位数字的分组中。
步骤2:计算目标项在分组内的偏移量
接下来算它在38位分组里是第几个:偏移量offset = 10¹⁸ - S(37) = 10¹⁸ - 675425858836496000 = 324574141163504000
这里的offset是从1开始计数的,比如offset=1就是38位分组的第一个项(38个1组成的字符串)。
步骤3:进制转换映射出结果
38位分组的项按字典序排列,等价于把0到3³⁸-1的数字用三进制表示(补前导0到38位),再将每一位加1(0→1,1→2,2→3)。
因为offset是1-based索引,我们需要先转成0-based:
- 取
num = offset - 1 = 324574141163503999 - 将num转换成38位三进制字符串,不足位补前导0
- 把字符串中的
0替换为1,1替换为2,2替换为3 - 最终字符串就是第10¹⁸项。
Python代码实现
Python支持任意大整数,完全能处理这个计算:
target = 10**18 # 步骤1:找到目标项所在的数字长度n total = 0 n = 0 while total < target: n += 1 total += 3 ** n # 步骤2:计算分组内的偏移量 offset = target - (total - 3 ** n) # 步骤3:转换为三进制并映射为1/2/3 num = offset - 1 ternary_digits = [] temp = num for _ in range(n): ternary_digits.append(str(temp % 3)) temp = temp // 3 # 反转得到正确顺序,补前导0到n位 ternary_str = ''.join(reversed(ternary_digits)).zfill(n) # 映射每一位 result = ''.join(str(int(c) + 1) for c in ternary_str) print("第10^18项是:", result)
小例子验证
比如找第4项:
- 前1位总项数是3,4>3,故n=2
- offset=4-3=1,num=0
- 三进制为
00,映射后是11,与序列一致,正确。
再比如第12项:
- 前2位总项数是12,offset=12-3=9,num=8
- 三进制为
22,映射后是33,正确。
内容的提问来源于stack exchange,提问作者Rahul Gupta
相关产品推荐
相关产品推荐

