简体   繁体   English

查找由数字组成的 N 位数字的计数,总和等于 K。返回计数,最小和最大数字

[英]Find count of N-digits numbers which consist of digits give you the sum is equal to K. Return count, the smallest and the largest number

I am finding for the effecient solution on that task我正在寻找该任务的有效解决方案
You are given K is summ of digits are in number and N is count of digits in the number.给定 K 是数字的总和,N 是数字的位数。
So you have to find count of all numbers, the smallest number and the largest number.所以你必须找到所有数字的计数,最小的数字和最大的数字。
Also It has to be sorted number.它也必须是排序的数字。 For example:例如:

145 - sorted number, because 4 > 1, and 5 > 4.
382 - not sorted number, because 3 < 8, but 8 > 2.

Everything must correspond to the condition of the problem. 一切都必须与问题的条件相对应。
Here is what I did: 这是我所做的:
 def find_all(sum_dig, digs): min_num = 10000000000000000 max_num = -1 count = 0 for i in range((10 ** digs // 10), 10 ** digs): summ = 0 for j in range(len(str(i))): summ += int((str(i))[j]) if summ == sum_dig and str(i) == ''.join(sorted(str(i))): count += 1 if i > max_num: max_num = i if i < min_num: min_num = i if count == 0: return [] else: return [count, min_num, max_num]

But that code works pretty slow, I get the error Execution Timed Out (12000 ms)但是该代码运行速度很慢,我收到错误Execution Timed Out (12000 ms)
Could you tell is there any way to make it more effecient?你能告诉有什么办法让它更有效吗?
Any advices are appreciated!任何建议表示赞赏!

Rather than iterating for every number from 10^(digs-1) until 10^digs , which will have a broad search space, we can iterate by adding the digit in a non-decreasing manner one by one from the leftmost digit to the rightmost digit (or non-increasing manner from right to left if you prefer it).与其迭代从10^(digs-1)10^digs的每个数字,这将具有广泛的搜索空间,我们可以通过以非递减方式从最左边的数字到最右边的数字一个一个地添加数字来迭代数字(如果您愿意,也可以从右到左非递增方式)。 Reference 参考

I tested the python code below on the site and it seems to solve the task.我在网站上测试了下面的 python 代码,它似乎解决了这个任务。

I think the time complexity of this code can still be improved.我认为这段代码的时间复杂度还是可以提高的。

You can try searching about top-down dynamic programming and memoization technique if you want to optimize it.如果您想优化它,您可以尝试搜索自顶向下的动态编程和记忆技术。

def find_all(sum_dig, digs):
    global total_count, lowest_value, greatest_value
    
    total_count = 0
    lowest_value = -1
    greatest_value = -1
    
    # complete search via depth first search
    def dfs(digit_sum, digit_count, num, digit_from):
        global total_count, lowest_value, greatest_value
        
        # base case
        if digit_count == digs:
            if digit_sum == sum_dig:
                if lowest_value == -1:
                    lowest_value = num
                greatest_value = num
                total_count += 1
            return
        
        # try all possible values one by one
        for i in range(digit_from, 10):
            dfs(digit_sum + i, digit_count + 1, num * 10 + i, i)
    
    dfs(0, 0, 0, 1)
    
    answer = []
    if total_count > 0:
        answer = [total_count, lowest_value, greatest_value]
    return answer
    

You could use a recursive approach that collects 1 digit at a time into a list until it reaches the specified total returning the value if its sum matches correctly.您可以使用递归方法,一次将 1 位数字收集到列表中,直到达到指定的总数,如果其总和正确匹配,则返回该值。 Then we can make heavy use of filtering to avoid testing numbers that we know will either exceed the target sum or are not in increasing order, cutting down the potential amount of values we have to check significantly.然后我们可以大量使用过滤来避免测试我们知道将超过目标总和或不按递增顺序的数字,从而减少我们必须显着检查的潜在值数量。

I tested on the website and it does pass all tests within the allotted time.我在网站上进行了测试,它确实在规定的时间内通过了所有测试。

The find_all function merely takes the result and puts it into the format required by the challenge. find_all function 仅获取结果并将其放入挑战所需的格式。

def find_all(sum_dig, digs):
    result = find_count(sum_dig, digs, [])
    size, sm, lg = len(result), min(result), max(result)
    return [size, sm, lg]


def find_count(sum_dig, digs, lst=[]):
    if len(lst) == digs:
        if sum(lst) == sum_dig:
            return [int(''.join([str(i) for i in lst]))]
        return []
    combos = []
    start = 1 if not len(lst) else lst[-1]
    for i in range(start, 10):
        t = 0 if not lst else sum(lst)
        if t + i <= total:
            combos += find_count(sum_dig, digs, lst + [i])
    return combos

Here's my take with a function for each value required, which seems to pass the tests (when returning an empty list if the partition count is zero).这是我对每个所需值的 function 的看法,这似乎通过了测试(如果分区计数为零,则返回空列表时)。

For the number of results, we can modify the recursion for partitions with restricted number of parts: take (1) the count of all partitions of nk into k parts that have largest part at most l-1 and add to them (2) the count of all partitions of n-1 into k-1 parts that have largest part at most l .对于结果的数量,我们可以修改部分数量受限的分区的递归:取(1)将nk的所有分区的计数分成最大部分最多为l-1k个部分,并添加到它们(2)将n-1的所有分区计数为k-1部分,其中最大部分为l (For each part in (1) add 1, for a total of k 1 s. For each partition in (2), add a part 1 .) O(n, k) search space. (对于(1)中的每个部分加 1,总共k 1 s。对于(2)中的每个分区,添加部分1O(n, k)搜索空间。

def f(n, k, l, memo={}):
  if k == 0 and n == 0:
    return 1

  if n <= 0 or k <= 0 or l <= 0:
    return 0

  if (n, k, l) in memo:
    return memo[(n, k, l)]

  memo[(n, k, l)] = f(n - k, k, l-1, memo) + f(n - 1, k - 1, l, memo)

  return memo[(n, k, l)]

For the smallest, we can use a greedy O(n) approach from left to right, always picking the smallest possible digit.对于最小的,我们可以使用从左到右的贪心O(n)方法,总是选择可能的最小数字。

def g(n, k):
  if k == 0:
    return 0

  next_digit = max(1, n - 9 * (k - 1))

  return next_digit * 10 ** (k - 1) + g(n - next_digit, k - 1)

For the largest, I couldn't think of a better approach than a recursion that limits the choice for the digit based on the current state.对于最大的情况,我想不出比基于当前 state 限制数字选择的递归更好的方法。 O(n, k)

from math import ceil

def h(n, k, largest):
  if n < 0:
    return 0

  if k == 1:
    return n

  best = 0
  digit = 0
  
  for i in range(
    min(largest, n - k + 1),
    min(largest, ceil(n / k)) - 1,
    -1):
    candidate = h(n - i, k - 1, i)
    if candidate > best:
      best = candidate
      digit = i

  return digit + 10 * best

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 计数范围内的位数与乘积相同 - Count numbers in range which sum of digits is same as product 打印1到N-数字计数 - Print 1 to N - Digits Count 如何统计不同基数中的数字位数? - How to count the number of digits in numbers in different bases? 详细解释“相邻位数绝对差不超过K的N位数字的计数”的逻辑 - Explain the logic of 'Count of N-digit numbers with absolute difference of adjacent digits not exceeding K' in Detail 如何找到不能被 3 整除的最小 n 位数? - How can I find the smallest number of n digits that is not divisible by 3? 用数字而不是数字来计数 - count increase by number, not digits 找到最大回文数的最快算法,它是具有相同位数的 2 个数字的乘积 - Fastest algorithm to find the largest palindrome that is the product of 2 numbers with the same number of digits 使用 lambda 函数对数字求和并计算数字 - Using lambda functions to sum digits and count digits 从其他数字的最小数字创建数字 - Creating a number from smallest digits of other numbers 我如何优化这个递归 function 来计算其数字等于总和的 n 位十六进制数的数量? - How do I optimize this recursive function that counts the number of n-digit hexadecimal numbers whose digits equal a sum?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM