首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >六种面额变化的快速算法:面试实践

六种面额变化的快速算法:面试实践
EN

Stack Overflow用户
提问于 2017-09-10 05:35:54
回答 1查看 134关注 0票数 2

我找到了这个问题的解决方案,但它需要O(n^2)。有可能做得更好吗?

问题:假设我们想找D美元的零钱。我们有一个含有N个元素的数组A。这些面额以美元值的形式存在于数组中,但我们不知道确切的高级面额。然而,我们得到了0< Aj < 125*N的限制条件是,我们每种面额中只有6种面额,我们必须能够确定我们是否可以使用精确地给出6总钞票(我们可以重复纸币并假定票据是任何类型的,所以我们可以有4美元纸币)。

如果A= 3,4,6,5,20,18,10,30和D= 50。然后,该算法返回自5+5+5+5+10+20以来的true。

我的尝试:

我试着排序然后再除法,但后来我陷入困境,因为我不知道如何消除可能的选择,因为我不知道数组中的确切内容。更好的是,如果没有在O(n^2)时间内显式地进行,我不知道如何肯定地说它是不可能的。我知道我被限制在6张钞票上,这有可能利用这个事实吗?

EN

回答 1

Stack Overflow用户

发布于 2017-09-10 08:10:12

在我看来,这是一个典型的递归问题。让我们编写一个函数,检查我们是否可以对D美元进行更改。为此,我们将取第一张钞票(假设是3美元),从D中删除它,然后递归地检查是否可以对D - 3美元进行更改。

如果我们不检查我们已经检查过的组合,我们可以更快地解决这个问题。因此,如果我们已经知道账单3, 5, 10不适合我们的需要,那么我们也不需要检查组合5, 10, 3。为此,我们首先需要对A数组进行排序,然后将最后使用的票据数(last_bill_id)传递给check函数。在函数中,我们不需要检查数字小于last_bill_id的任何组合。

python中的完整解决方案:

代码语言:javascript
复制
A = [3, 4, 6, 5, 20, 18, 10, 30]
D = 50


def check(counters, current_sum, depth, last_bill_id):
    global A
    if depth > 6:  # max amount of bills is 6
        return False
    if depth == 6:  # we used 6 bill, did we get the correct sum?
        return current_sum == 0
    if current_sum <= 0:  # we gave too much change
        return False
    # current_sum > 0 and depth < 6
    for i in xrange(last_bill_id, len(A)):
        if counters[i] < 6:
            # we can use i-th bill another time
            counters[i] += 1
            if check(counters, current_sum - A[i], depth + 1, i):
                return True
            counters[i] -= 1
    return False


# init counters with zeros
counters = [0] * len(A)
# check if we can change for `D`
A = sorted(A)  # sort A before the function
print 'Can make change:', check(counters, D, 0, 0)
# print bills with counters
for i, c in enumerate(counters):
    if c > 0:
        print '$%d x %d' % (A[i], c)

输出:

可以做出改变:真的 $3x4 $18x1 $20x1

编辑

以前的解决方案具有复杂性O(n^6)。但是实际上,我们可以使用回忆录 (或者,我们用另一种方式,动态规划)使它变得更快。让我们对A数组进行排序,并将其中的每个数字重复6次,这样我们就可以得到类似于A = [3, 3, 3, 3, 3, 3, 5, 5, ...]的内容。现在让我们填充3D矩阵M[,,],其中M[bills_num, i, d]true当且仅当我们可以用从A数组的i-th位置开始的bills_num票据对d美元进行更改。结果将出现在单元格M[6, 0, D]中。该矩阵的大小为6 x (6 * n) x D,因此我们可以在O(6 * (6 * n) * D) == O(n * D)时间内填充它(使用类似于前面的解决方案的递归方法)。python的代码:

代码语言:javascript
复制
A = [3, 4, 6, 5, 20, 18, 10, 30]
D = 50

# sort A and repeat 6 times
A = sorted(A * 6)
# create matrix M, where:
# 0 == uncomputed, 1 == True, -1 == False
arr1d = lambda x: [0] * x
arr2d = lambda x, y: [arr1d(y) for i in xrange(x)]
arr3d = lambda x, y, z: [arr2d(y, z) for i in xrange(x)]
M = arr3d(6 + 1, len(A), D + 1)


def fill_m(bills_num, start_pos, d):
    global A, M
    if d == 0:  # can make change for 0 only with 0 bills
        return True if bills_num == 0 else False
    if d < 0 or bills_num <= 0 or start_pos >= len(A):
        return False
    if M[bills_num][start_pos][d] == 0:
        # need to compute cell value
        if fill_m(bills_num, start_pos + 1, d):
            M[bills_num][start_pos][d] = 1
        elif fill_m(bills_num - 1, start_pos + 1, d - A[start_pos]):
            M[bills_num][start_pos][d] = 1
        else:
            M[bills_num][start_pos][d] = -1
    return M[bills_num][start_pos][d] == 1


print 'Can make change for $', D, fill_m(6, 0, D)
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46137611

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档