餐厅菜单和收据的最佳解决方案

问题描述

我最近遇到了这个问题。

” 我去过一家餐馆点菜,但我忘记了过去的点菜。我只记得我花了多少钱。

从以下菜单和收据值列表中,确定我可以订购的东西。 '''

primary_menu = { 蔬菜三明治:6.85, '额外的蔬菜':2.20, '鸡肉三明治':7.85, '额外的鸡':3.20, '奶酪':1.25, “筹码”:1.40, '玉米片':3.45, '苏打水':2.05, }

reversed_primary_menu = { 6.85:“素食三明治”, 2.20:“额外的蔬菜”, 7.85:“鸡肉三明治”, 3.20:“额外的鸡肉”, 1.25:“奶酪”, 1.40:“筹码”, 3.45:“玉米片”, 2.05:“ soda”, }

''' 这是我在餐厅订的9种不同订单的收据清单 ''' 收据= [4.85,11.05,13.75,17.75,18.25,19.40,28.25,40.30,75.00]

''' 约束:

  • 您必须使用收据价值的100%,我们不希望有剩余的钱
  • 您可以订购任何数量的任何菜单项
  • 所有收据值都不是“技巧”,它们都有答案

找到加起来就是收据总数的第一个食物组合,只打印出该收据的一个组合,然后转到下一个收据。

输出格式取决于您,但是下面是一些示例:

4.85: 3种食物,额外的蔬菜,薯条,奶酪

13.75: 3个项目,{'素食三明治':1,'玉米片':2}

示例: 4.85收据具有三种可能的组合:

  • 最佳:玉米片,薯条(共2件)
  • 额外的蔬菜,薯条,奶酪(总共3次)
  • 薯片,薯片,汽水(共3件) '''

现在有两种解决方案。

  1. 对字典进行排序
  2. 直接递归剩余金额。
  3. 这里的问题是,一次递归传递还不够好(如果我们需要多个相同的条目),即我将字典中的第一个条目取走,然后尝试递归地找到下一个适合收据的条目,如果还有剩余,递归地找到适合剩余量的元素。
  4. 在上面的递归调用中,我将第一个项固定到第二级,然后将剩余金额检查为
  5. 我也必须在第一级上完成4)。
class Solution:
    def getItems(self,orev: dict,remain: int) :
        rev = collections.OrderedDict(sorted(orev.items()))
        list = []

        for i in rev:
            list = self.getMine(rev,round(remain-i,2))
            if list != [-1]:
                list.append(rev[i])
                return list

        return list

    def getMine(self,rev: dict,remain: int):

        list = []

        if remain < 0:
            retlist = [-1]
            return retlist

        if remain in rev:
            list.append(rev[remain])
            return list

        for i in rev:
            retlist = self.getMine(rev,2))

            if retlist != [-1]:
                list.extend(retlist)
                list.append(rev[i])
                return list
        return [-1]

第二种方法是使用BST,但与上述方法相同

我觉得这意味着我们正在做n ^ n。

我不知道如何优化它。

解决方法

您在正确的轨道上。您知道还剩多少美元以及您在哪个项目上的递归是一个很好的起点,但是,不只是通过获取或离开当前项目进行递归,还应先递减0,然后取1,然后取2,等等等等。如果在任何时候还剩$ 0,请打印出当前有多少项并返回True,但是如果到达最后一项仍不能使它工作,请返回False 。时间的复杂性将是模糊的,但肯定可以。

您可以使用称为“动态编程”的技术来提高性能。您会做的是,请注意,在任何时候,如果您正在查看商品5,而您还有$5.63,那么您就不在乎如何 ,并且可以继续解决该问题,就好像以前的项目根本不存在一样。此外,如果您将答案保存为[项目5,金钱5.63],那么如果您以其他方式到达那里,则无需做任何其他工作,只需立即返回保存的答案即可。如果这样做,您的时间复杂度将为O(n*m),其中n是项目数,m是不同的允许货币可能性的总数(在这种情况下,是输入货币,以美分计)。这种方法的实现更加深入,但是您可以通过Google 动态编程更好地了解这里发生的事情。

,

这是我在interviewing.io上最喜欢的模拟面试问题之一,我在那里向OP提出了这个挑战。

您可以使用 DFS、BFS、DP 或蛮力解决它,但回溯组件对于正确解决至关重要。进行递归会产生更少的代码,并且记忆会加快它的速度,但是如果你采用自下而上的方法(从 $0 开始并计算到收据值),记忆会容易得多,而不是从收据值开始直到你到 0。

问题的第一部分是“找到任何答案”,问题的第二部分是“找到最小的项目列表”。在这一点上,您可以采用 Coin Change 的策略,在那里您采取贪婪的方法并首先花钱购买昂贵的东西。这并不总是立即为您提供最佳答案,但与按价格升序对菜单进行排序相比,您会更接近最小的答案。

通过查看最大深度原则,还有其他快捷方式可以适应如何更快地解决问题。例如,如果您的最佳答案是 10 个项目,为什么要建立一个完整的 20 个项目列表(这仍然使您自上而下达到 0 美元,或自下而上达到确切的收据金额)然后才意识到它不是“更好”的答案是更短的项目列表。

第二部分的常见入门级方法是收集“每个”答案并在结果列表中找到最小的答案,但在最近对该问题的改编中,您最终会得到数百万种组合和排列。但是,如果您有“额外的蔬菜、薯条、奶酪”的答案,您必须找到“奶酪、薯条、额外的蔬菜”的排列组合,才能确定最终是完全相同的列表。

如果我们在模拟面试后得到介绍,您应该可以访问我的电子邮件地址,我很乐意就此问题保持联系并讨论其他想法。或者更好的是,您可以要求 IIO 支持团队再次配对我们。 :)

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...