Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/365.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 计算小数表示形式中具有升序连续数字的范围内的数字_Python_Algorithm - Fatal编程技术网

Python 计算小数表示形式中具有升序连续数字的范围内的数字

Python 计算小数表示形式中具有升序连续数字的范围内的数字,python,algorithm,Python,Algorithm,如果整数在其十进制表示中至少有三个升序连续数字,则它是一个特殊数字 连续顺序中的三位数字必须大于零 例如:123,45123,245789,123456789,12345是特殊的数字,012,1012,1245是非特殊的数字 我必须计算在给定的S到E之间存在的特殊数字的数量。(1 是否存在任何此类解决方案 这样的解决方案当然存在,并且可以有效地计算s和E之间的特殊数字,即使s和E比10**18大得多。例如,我们将在下面看到确切的2685401982839147497953997698765007

如果整数在其十进制表示中至少有三个升序连续数字,则它是一个特殊数字

连续顺序中的三位数字必须大于零

例如:
123
45123
245789
123456789
12345
特殊的
数字,
012
1012
1245
非特殊的
数字

我必须计算在给定的
S
E
之间存在的特殊数字的数量。(
1
是否存在任何此类解决方案

这样的解决方案当然存在,并且可以有效地计算
s
E
之间的特殊数字,即使
s
E
10**18
大得多。例如,我们将在下面看到确切的
26854019828391474979539976987650077000644049724
特殊数字rs小于
10**50
,因此所有50位数字中约有四分之一是特殊数字

我将概述解决方案的想法,然后给出一些Python代码

首先是简单的部分:对于任何非负整数
n
,能够计算范围(n)
中的特殊数字就足够了。也就是说,我们只需要一个函数:

def count_special_below(n: int) -> int:
    """
    Return count of special numbers m satisfying 0 <= m < n.
    """
    # See below for implementation
def count_special_between(start: int, end: int) -> int:
    """
    Return count of special numbers m satisfying start <= m <= end.
    """
    return count_special_below(end + 1) - count_special_below(start)
def count_special_below(n: int) -> int:
    """
    Return count of special numbers m satisfying 0 <= m < n.
    """
    n_counts, n_cls = [0] * 16, 0
    for digit in map(int, str(n)):
        m_counts = [0] * 16
        for tc, count in zip(transitions, n_counts):
            for tcs in tc:
                m_counts[tcs] += count
        for t in transitions[n_cls][:digit]:
            m_counts[t] += 1
        n_counts, n_cls = m_counts, transitions[n_cls][digit]

    return n_counts[15]
想法 我们将非负整数分成几个类。其中一类是特殊数,其余的是各种形式的非特殊数。除法的方式是,我们知道当我们添加一个给定的数字时,任何给定整数的类是如何变化的

具体而言,我们定义了16个互斥类,编号从0到15,如下所示:

  • 类15包含所有特殊编号
  • 类别14包含以数字“78”结尾的所有非特殊数字
  • 类13包含以数字“67”结尾的所有非特殊数字
  • 类别12包含以数字“56”结尾的所有非特殊数字
  • 类11包含以数字“45”结尾的所有非特殊数字
  • 类别10包含以数字“34”结尾的所有非特殊数字
  • 类别9包含以数字“23”结尾的所有非特殊数字
  • 第8类包含以数字“12”结尾的所有非特殊数字
  • 类7包含所有以“7”结尾的非特殊数字,但不包含“67”
  • 第6类包含所有以“6”结尾的非特殊数字,但不包括“56”
  • 第5类包含所有以“5”结尾的非特殊数字,但不包括“45”
  • 类别4包含所有以“4”结尾的非特殊数字,但不包含“34”
  • 类别3包含所有以“3”结尾的非特殊数字,但不包含“23”
  • 类别2包含以“2”结尾的所有非特殊数字,但不包括“12”
  • 类1包含以“1”结尾的所有非特殊数字
  • 类0包含以“8”、“9”或“0”结尾的所有非特殊数字,但不以“78”结尾
这些类的要点是,如果对一些
q
r
n=10*q=r
,那么我们可以计算
n
的类,只知道
q
的类和
r
的值:我们不需要知道
q
本身

例如,如果
q
在类
9
r=4
,那么
n=10*q+r
在类15中:这是特殊的。而如果
q
在类
9
r=5
,那么
n
在类
5
,如果
q
在类
9
r=0>
n
在类
0

我们可以通过所有160个(类、数字)组合来计算转换,然后将这些转换记录在一个简单的列表中

现在我们可以将其放大:再次假设
n=10*q+r
,并且我们已经(例如递归地)计算了
范围(q)
中属于16个类中每一类的整数的数量。然后我们可以使用转移矩阵来计算
范围(n)中的整数的数量
属于16类中的每一类

例如,如果
n=135457
q=13545
r=7
,则
range(q)
中类
9
的值的数量变成
121
。这些
121
值中的每一个值都恰好为
range(135457)贡献一个特殊数字
,通过添加
4
。还有
135
8
的值,它们同样在
范围(135457)
中贡献一个特殊的数字。通过添加贡献,并注意考虑范围
范围(135450135457)
,我们得到
范围(135457)
中每个类的总计数

Python代码 这是迭代形式的代码。递归地表达它比迭代地表达更自然,但是对于非常大的起始值和结束值(例如有数千位数字),我们会遇到Python的递归限制

首先是转换矩阵:这是一个列表列表,行对应于16个类,列对应于数字。如果
q
具有class
c
,则
10*q+r
具有class
转换[c][r]

transitions = [
    [0, 1, 2, 3, 4, 5, 6, 7, 0, 0],
    [0, 1, 8, 3, 4, 5, 6, 7, 0, 0],
    [0, 1, 2, 9, 4, 5, 6, 7, 0, 0],
    [0, 1, 2, 3, 10, 5, 6, 7, 0, 0],
    [0, 1, 2, 3, 4, 11, 6, 7, 0, 0],
    [0, 1, 2, 3, 4, 5, 12, 7, 0, 0],
    [0, 1, 2, 3, 4, 5, 6, 13, 0, 0],
    [0, 1, 2, 3, 4, 5, 6, 7, 14, 0],
    [0, 1, 2, 15, 4, 5, 6, 7, 0, 0],
    [0, 1, 2, 3, 15, 5, 6, 7, 0, 0],
    [0, 1, 2, 3, 4, 15, 6, 7, 0, 0],
    [0, 1, 2, 3, 4, 5, 15, 7, 0, 0],
    [0, 1, 2, 3, 4, 5, 6, 15, 0, 0],
    [0, 1, 2, 3, 4, 5, 6, 7, 15, 0],
    [0, 1, 2, 3, 4, 5, 6, 7, 0, 15],
    [15, 15, 15, 15, 15, 15, 15, 15, 15, 15],
]
下面是完整的
count\u special\u
功能:

def count_special_below(n: int) -> int:
    """
    Return count of special numbers m satisfying 0 <= m < n.
    """
    # See below for implementation
def count_special_between(start: int, end: int) -> int:
    """
    Return count of special numbers m satisfying start <= m <= end.
    """
    return count_special_below(end + 1) - count_special_below(start)
def count_special_below(n: int) -> int:
    """
    Return count of special numbers m satisfying 0 <= m < n.
    """
    n_counts, n_cls = [0] * 16, 0
    for digit in map(int, str(n)):
        m_counts = [0] * 16
        for tc, count in zip(transitions, n_counts):
            for tcs in tc:
                m_counts[tcs] += count
        for t in transitions[n_cls][:digit]:
            m_counts[t] += 1
        n_counts, n_cls = m_counts, transitions[n_cls][digit]

    return n_counts[15]
但是,我们的新功能也可以很好地处理大量数据:

>>> count_special_between(0, 10**50)
26854019828391474979539976989876500770006474049724
在我的机器上,即使是计算低于
10**10000
的特殊数字也只需要一两秒钟,但由于答案正好是
10000
位(毫不奇怪,因为“大多数”大数字都是特殊的),我就不在这里了

与正则表达式的连接 众所周知,通过正则表达式进行匹配(在stri
>>> from greenery.lego import parse
>>> p = parse("[0-9]*(123|234|345|456|567|678|789)[0-9]*")
>>> p.to_fsm()
fsm(
    alphabet = {'2', '1', '7', anything_else, '0', '4', '8', '3', '5', '6', '9'},
    states = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
    initial = 0,
    finals = {15}, map = {
        0: {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 0, '9': 0},
        1: {'0': 0, '1': 1, '2': 8, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 0, '9': 0},
        2: {'0': 0, '1': 1, '2': 2, '3': 9, '4': 4, '5': 5, '6': 6, '7': 7, '8': 0, '9': 0},
        3: {'0': 0, '1': 1, '2': 2, '3': 3, '4': 10, '5': 5, '6': 6, '7': 7, '8': 0, '9': 0},
        4: {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 11, '6': 6, '7': 7, '8': 0, '9': 0},
        5: {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 12, '7': 7, '8': 0, '9': 0},
        6: {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 13, '8': 0, '9': 0},
        7: {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 14, '9': 0},
        8: {'0': 0, '1': 1, '2': 2, '3': 15, '4': 4, '5': 5, '6': 6, '7': 7, '8': 0, '9': 0},
        9: {'0': 0, '1': 1, '2': 2, '3': 3, '4': 15, '5': 5, '6': 6, '7': 7, '8': 0, '9': 0},
        10: {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 15, '6': 6, '7': 7, '8': 0, '9': 0},
        11: {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 15, '7': 7, '8': 0, '9': 0},
        12: {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 15, '8': 0, '9': 0},
        13: {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 15, '9': 0},
        14: {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 0, '9': 15},
        15: {'0': 15, '1': 15, '2': 15, '3': 15, '4': 15, '5': 15, '6': 15, '7': 15, '8': 15, '9': 15}})