【问题标题】:Count occurrences of digit 'x' in range (0,n]计算范围内数字“x”的出现次数 (0,n]
【发布时间】:2015-09-16 04:00:51
【问题描述】:

所以我正在尝试编写一个 python 函数,它接受两个参数 n 和 num,并计算 0 和 num 之间出现的“n”。例如,

countOccurrences(15,5) 应该是2

countOccurrences(100,5) 应该是20

我对这个问题做了一个简单的迭代解决方案:

def countOccurrences(num,n):
  count=0
  for x in range(0,num+1):
    count += countHelper(str(x),n)
  return count

def countHelper(number,n):
  count=0
  for digit in number:
    if digit==n:
      count += 1
  return count

如果我尝试调用countOccurrences(100000000000,5),这会遇到明显的问题。 我的问题是如何提高效率?我希望能够“相当”快速地处理问题,并避免内存不足错误。这是我第一次尝试这样做的递归解决方案:

def countOccurence(num, n):
  if num[0]==n:
    return 1
  else:
    if len(num) > 1:
      return countOccurence(num[1:],n) + countOccurence(str((int(num)-1)),n)
    else:
      return 0

【问题讨论】:

  • 如果这是 Python 2.x,请使用 xrange。递归只是意味着你达到了系统递归限制。
  • 我相信正确的解决方案可能比这更聪明。我想如果不是 O(1),这可以在 O(log n) 中完成。
  • 我同意其他凯文的观点。我记得在编程挑战网站(Project Euler???)上看到这个问题,解决方案是递归和对数。
  • 您可以使用与此非常相似的解决方案来获得 O(log n):stackoverflow.com/questions/22394257/…

标签: python algorithm memory-management


【解决方案1】:

这不会遇到任何内存问题,直到 max_num 小到足以放入 C long 中。基本上它仍然是一种蛮力算法,尽管针对 Python 进行了显着优化。

def count_digit(max_num, digit):
    str_digit = str(digit)
    return sum(str(num).count(str_digit) for num in xrange(max_num+1))

【讨论】:

    【解决方案2】:

    我已经修复了我的解决方案,希望它符合您的要求。让我们看一下第一个辅助函数:

    def splitNumber(num):
        temp = str(number)
        nums = list(temp)
        return nums
    

    此函数创建一个字符串列表,其中包含数字输入中的所有单个数字。例如,

    splitNumber(100)
    

    会返回:

    ['1', '0', '0']
    

    从这里,您调用主函数并使用此主函数测试每个单独的数字:

    def countOccurences(num, n):
        count = 0
        for x in range(0, (num + 1)):
            temp = splitNumber(x)
            for x in range(len(temp)):
                if (temp[x] == str(n)):
                    count = count + 1
        return count
    

    这应该给出所需的输出。让我知道这是否适合您!

    【讨论】:

    • 您的解决方案中仍然存在内存问题。除此之外,您不会摆脱额外的 Python 函数调用和 for 循环。换句话说,您的解决方案与 OP 的解决方案一样低效。
    • 这只是上述解决方案的一个较慢版本,它本身很慢
    【解决方案3】:

    见:https://math.stackexchange.com/a/1229292/974150

    在python中:

    def counts_of_i_bf(n, i):
        """Counts the number of occurences in a range [0 .. n] of
            the digit i [0...9]
    
        Args:
            n ([int]): upper value of range [0 ... n]
            i ([type]): digit looking for [0.. 9]
    
        Returns:
            [int]: occurences of i in the range [0...n]
        """
        return sum(str(d).count(str(i)) for d in range(n + 1))
    
    def counts_of_i_dp(n, i):
        """Counts the number of occurences in a range [1 .. n] of
            the digit i [1...9] by implementing the recurrence
            relation:
                            | ak.10^(k-1) + fi(b)           if a < i
            fi(a.10^k +b) = | ak.10^(k-1) + 1 + fi(b) + b   if a == i
                            | (ak + 10).10^(k-1) + fi(b)    if a > i
    
        see: https://math.stackexchange.com/a/1229292/974150
        Args:
            n ([int]): upper value of range [1 ... n]
            i ([type]): digit looking for [1.. 9]
    
        Returns:
            [int]: occurences of i in the range [0...n]
        """
        som = 0
        while n > 0:
            k = int(log10(n))
            a = n // 10**k
            b = n - a * 10**k
            if a < i:
                som += a*k*10**(k-1)
            elif a == i:
                som += a*k*10**(k-1) + 1 + b
            else:
                som += (a*k + 10)*10**(k-1)
            n = b
            
        return int(som)
    
    def counts_of_0(n):
        """Counts the number of occurences in a range [1 .. n] of
            the digit0 by implementing:
            Tn = (k + 1)*(b + 1 + (a - 1)10^k) + ∑ 9*s*10(s - 1) for s=1.. k\
            f0(n) = Tn -∑ 9s.10^(s-1) for s=1..9
      
            see: https://math.stackexchange.com/a/1229292/974150
        Args:
            n ([int]): upper value of range [1 ... n]
    
        Returns:
            [int]: occurences of 0 in the range [1...n]
        """
        k = int(log10(n))
        a = n // 10**k
        b = n - a * 10**k
        Tn = (k + 1)*(b + 1 + (a - 1)*10**k) + sum(9*s*10**(s - 1) for s in range(1, k + 1))
        return Tn - sum(counts_of_i_dp(n, i) for i in range(1, 10)) + 1 # was one of
    
    
    def counts_of_i(n, i):
        """Counts the number of occurences in a range [0 .. n] of
            the digit i [0...9]
            
    
        Args:
            n ([int]): upper value of range [0 ... n]
            i ([type]): digit looking for [0.. 9]
    
        Returns:
            [int]: occurences of i in the range [0...n]
        """
        if n == 0: return 1 if i == 0 else 0
        if i == 0: return counts_of_0(n)
        return counts_of_i_dp(n, i)
    
    assert all(counts_of_i_bf(i, d) == counts_of_i(i, d) for i in range(1_001) for d in range(10))
    

    【讨论】:

    • 这看起来很有希望,但是对算法的一些解释会很有用。另外,counts_of_i_dp(10,0) 返回的值是 11,这是不对的。
    猜你喜欢
    • 2020-11-09
    • 2017-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多