在以下字符串中找到第n个位置的数字的有效算法是什么
112123123412345123456 ... 123456789101112 ...
将整个字符串存储在内存中对于非常大的n是不可行的,所以我正在寻找一种能够在上面的字符串中找到第n个数字的算法,如果n非常大(即只是生成第一个数字的替代方法) n个数字的字符串)。
答案 0 :(得分:3)
这里有几个级别:数字是数字x的一部分,数字x是序列1,2,3 ... x ... y的一部分,该序列是序列块的一部分导致y等具有z数字的数字。我们将逐一解决这些问题。
有9个数字,1位数:
first: 1 (sequence length: 1 * 1)
last: 9 (sequence length: 9 * 1)
average sequence length: (1 + 9) / 2 = 5
1-digit block length: 9 * 5 = 45
有90个数字,2位数字:
first: 10 (sequence length: 9 * 1 + 1 * 2)
last: 99 (sequence length: 9 * 1 + 90 * 2)
average sequence length: 9 + (2 + 180) / 2 = 100
2-digit block length: 90 * 100 = 9000
有900个数字,包含3位数字:
first: 100 (sequence length: 9 * 1 + 90 * 2 + 1 * 3)
last: 999 (sequence length: 9 * 1 + 90 * 2 + 900 * 3)
average sequence length: 9 + 180 + (3 + 2,700) / 2 = 1,540.5
3-digit block length: 900 * 1,540.5 = 1,386,450
如果您继续计算这些值,您将找到您要查找的数字位于哪个数据块(最多可包含多少位数),并且您将知道开始和这个街区的终点。
说你想要百万分之一的数字。您发现它位于3位数字块中,并且该块位于以下总序列中:
start of 3-digit block: 45 + 9,000 + = 9,045
start of 4-digit block: 45 + 9,000 + 1,386,450 = 1,395,495
所以在这个区块中我们正在寻找数字:
1,000,000 - 9,045 = 990,955
现在您可以使用例如二进制搜索,找出第990,955位数字所在的序列;你从3位数字块中途的3位数字开始:
first: 100 (sequence length: 9 + 180 + 1 * 3)
number: 550 (sequence length: 9 + 180 + 550 * 3)
average sequence length: 9 + 180 + (3 + 1650) / 2 = 1,015.5
total sequence length: 550 * 1,015.5 = 558,525
哪个太小了;所以我们尝试550 * 3/4 = 825,看看它是太小还是大,然后以越来越小的步长向上或向下移动,直到我们知道990,995位数在哪个序列。
在数字n的序列中说出来;然后我们计算直到n-1的所有3位数序列的总长度,这将给出我们在数字n的序列中寻找的数字的位置。然后我们可以使用数字9 * 1,90 * 2,900 * 3 ...来找出数字所在的数字,然后是数字是什么。
答案 1 :(得分:0)
嗯,你有一系列序列,每个序列都增加一个数字。
如果你有" x"其中,直到那一点的序列占据x * (x + 1) / 2
个字符位置。或者,另一种说法是" x" s序列从x * (x - 1) / 2
开始(假设从零开始索引)。这些被称为三角数。
所以,你需要做的就是找到" x"累积金额最接近给定" n"的值。这有三种方式:
一旦知道值所在的序列,确定该值只是算术问题。
答案 2 :(得分:0)
我们希望能够搜索三种类型的结构,(1)连接d
位数字的序列,例如一位数字:
123456...
或3位数:
100101102103
(2)节中的行, 其中每个部分都基于添加到前缀的上一部分。例如,第1节:
1
12
123
...
或第3节:
1234...10111213...100
1234...10111213...100102
1234...10111213...100102103
<----- prefix ----->
和(3)完整的部分,尽管我们可以枚举完整的部分,因为它们呈指数增长,并有助于构建我们的部分前缀。对于(1),如果我们知道位数,则可以使用简单的除法;对于(2),我们可以进行二进制搜索。
这里的Python代码也可以回答那些大问题:
def getGreatest(n, d, prefix):
rows = 9 * 10**(d - 1)
triangle = rows * (d + rows * d) // 2
l = 0
r = triangle
while l < r:
mid = l + ((r - l) >> 1)
triangle = mid * prefix + mid * (d + mid * d) // 2
prevTriangle = (mid-1) * prefix + (mid-1) * (d + (mid-1) * d) // 2
nextTriangle = (mid+1) * prefix + (mid+1) * (d + (mid+1) * d) // 2
if triangle >= n:
if prevTriangle < n:
return prevTriangle
else:
r = mid - 1
else:
if nextTriangle >= n:
return triangle
else:
l = mid
return l * prefix + l * (d + l * d) // 2
def solve(n):
debug = 1
d = 0
p = 0.1
prefixes = [0]
sections = [0]
while sections[d] < n:
d += 1
p *= 10
rows = int(9 * p)
triangle = rows * (d + rows * d) // 2
section = rows * prefixes[d-1] + triangle
sections.append(sections[d-1] + section)
prefixes.append(prefixes[d-1] + rows * d)
section = sections[d - 1]
if debug:
print("section: %s" % section)
n = n - section
rows = getGreatest(n, d, prefixes[d - 1])
if debug:
print("rows: %s" % rows)
n = n - rows
d = 1
while prefixes[d] < n:
d += 1;
if prefixes[d] == n:
return 9;
prefix = prefixes[d - 1]
if debug:
print("prefix: %s" % prefix)
n -= prefix
if debug:
print((n, d, prefixes, sections))
countDDigitNums = n // d
remainder = n % d
prev = 10**(d - 1) - 1
num = prev + countDDigitNums
if debug:
print("num: %s" % num)
if remainder:
return int(str(num + 1)[remainder - 1])
else:
s = str(num);
return int(s[len(s) - 1])
ns = [
1, # 1
2, # 1
3, # 2
100, # 1
2100, # 2
31000, # 2
999999999999999999, # 4
1000000000000000000, # 1
999999999999999993, # 7
]
for n in ns:
print(n)
print(solve(n))
print('')