[英]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.
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-1
的k
个部分,并添加到它们(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)中的每个分区,添加部分1
) O(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.