【问题标题】:Efficient method to count the numbers that have at least one digit that repeating计算至少有一个数字重复的数字的有效方法
【发布时间】:2020-11-05 02:35:15
【问题描述】:

我正在尝试找到一种有效的方法来计算小于或等于某个数字 x 且至少有一个数字重复的正整数的数量。

我尝试计算具有重复数字的数字,然后从 x 中减去它,但我的程序对于 x 达到 10^10 时变得太慢了。

我搜索了一下,发现了两种实现这个想法的方法:

def count_unique(x): 
    cnt = 0
    for i in range (x + 1): 
        num = i
        visited = [0,0,0,0,0,0,0,0,0,0]
        while (num): 
            if visited[num % 10] == 1: 
                break
            visited[num % 10] = 1 
            num = (int)(num / 10)
        if num == 0: 
            cnt += 1
    return cnt -1
for i in range(int(input())):
    x = int(input())
    print(x - count_unique(x))

还有:

Prefix = [0] 
def repeated_digit(n): 
    a = [] 
    while n != 0: 
        d = n%10
        if d in a: 
            return 0
        a.append(d) 
        n = n//10
    return 1
def pre_calculation(MAX): 
    global Prefix 
    Prefix.append(repeated_digit(1)) 
    for i in range(2,MAX+1): 
        Prefix.append(repeated_digit(i)+Prefix[i-1]) 
MAX = 10000000000
pre_calculation(MAX) 
for i in range(int(input())):
    x = int(input())
    print(x - Prefix[x])

但不幸的是,它们都不够快,有没有人有更好的方法来实现这一点?

示例输入:

2    #number of test cases
10
20

样本输出:(每个测试用例的结果)

0   #no number less than 10 with a repeating digit
1   #one number less than 20 with a repeating digit (which is 11)

【问题讨论】:

  • 请输入输出示例!
  • @Ironkey 我马上添加,谢谢
  • 什么是“重复”数字? 11 很清楚,但是 121 呢? (我可以看到您在代码中选择了什么,但既然您是在寻求帮助,最好明确说明预期的行为)
  • 另一个问题:什么才是“高效”?你需要它尽可能快吗?还是使用尽可能少的代码?还是尽可能少的内存空间?
  • @Grismar 是的,重复数字可以在任何位置,例如 11 121 2220

标签: python algorithm


【解决方案1】:

您在解构数字和计算数字方面经历了很多痛苦。让我们简化这些步骤。给定一个整数num,获取单个数字,然后找到唯一数字:

digits = str(num)
unique_digits = set(digits)

现在,如果唯一数字的长度少于原始数字的长度,则表示重复。

我相信您可以从这里处理编码。

【讨论】:

  • 我认为循环每个数字 x 从 1 到 x 并创建一组数字来计算数字重复会更慢,或者我错过了什么?
  • 是的,这在 10^10 的规模上仍然会很慢。如果您希望在输入非常大的情况下快速运行,似乎您需要一个分析解决方案。
  • 这看起来更像是一个建议,因为它并没有解决处理大输入的问题
【解决方案2】:

我真的认为除非您尝试多次执行此操作,否则执行此操作不值得。如果是为了练习,我认为了解排列会很有用。

如何使用排列和组合。您会看到,通过排列,您可以计算排列某组数字的方式数量,无论是否重复。

好的,首先,每个 10 位以上的数字都有一个重复的数字。因此,您可以跳过计算 9,999,999,999 以上的所有内容

排列可以为您提供一组没有重复数字的方式的计数。 使用这个和一个简单的减法,你可以找到你想要的。 (您必须为每个位值、单位、十位、数百位...)(此外,您还必须消除以 0 开头的那些,并使用另一种排列)

现在,问题在于它只能准确计算只有 9 的那些。例如 9999,因为它计算所有可能性。假设您有一个 3999,为此您必须计算最后 3 位数字的可能性,而排列组中没有 3。然后用已经包含 3 的重复添加排列。然后重复 2999, 1999 并添加 999 的可能性。推理如下:

  • 如果第一个数字中已经有 3,如果再次出现则重复。因此,如果您计算没有 3 的排列。那么您可以将所有至少包含 3 的排列相加。

对于像 3244 这样的数字,您只需对 244 应用相同的内容...

我知道这不是一个简单的解决方案,而且可能会造成混淆,但它可以减少你对 log(n) 之类的任务。

祝你好运:)

你可以在google上搜索排列,这在数学中很常见。

【讨论】:

  • 一个小的修正——你可以跳过上面的所有内容:9,900,000,000
【解决方案3】:

我会尝试分析找出数字的互补,并使用这个值来计算最终结果。

考虑(对于,N = 请求输入):

1. X = #positive-integers with all unique digits
2. Create the algo to figure out X
3. Final result = N - X

这是我的工作代码:


def all_unique_numbers_with_n_digits(d: int):
    if d < 1:
        return 0
    count = 9
    dig = 9
    while d > 1:
        count *= dig
        dig -= 1
        d -= 1
    return count


def count_numbers_with_unique_digits_less_than_n(n: int):
    X = str(n)
    count = 0

    unique_digs = set(range(9))

    for i in range(1, len(X)+1):
        # print("i,", i, X)
        dig_value = int(X[i-1])
        dv = dig_value if i == len(X) else dig_value-1
        # print(X, i, dig_value, dig_multiplier, count)
        count += max(dv, 0) * all_unique_numbers_with_n_digits(len(X)-i)
        if dig_value in unique_digs:
            unique_digs.remove(dig_value)
        if i != len(X):
            count += all_unique_numbers_with_n_digits(len(X)-i)
        else:
            mval = 0
            for x in unique_digs:
                if dv >= x > mval:
                    mval = x
            count += mval

    return count


def numbers_with_atleast_1_dig_repeating(n: int):
    return n - count_unique(n)


print(count_numbers_with_unique_digits_less_than_n(9))
print(count_numbers_with_unique_digits_less_than_n(100))
print(count_numbers_with_unique_digits_less_than_n(101))

输出:

90
90
90

【讨论】:

    猜你喜欢
    • 2020-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-01
    • 1970-01-01
    • 2018-05-08
    • 1970-01-01
    相关资源
    最近更新 更多