当前位置: 首页 > 知识库问答 >
问题:

将低效的递归换币函数转换为迭代

袁子瑜
2023-03-14

我有一个低效的递归硬币变化函数,它计算出给定数量的硬币组合数量。如果可能的话,我想把它转换成一个更有效的迭代函数。

一个问题是,我正在使用回溯来尝试一个叫做面额的数组中的不同硬币。我也在使用记忆法,但当数量很大时,它不会加快速度。

这是我的密码:

unsigned long long CalculateCombinations(std::vector<double> &denominations, std::vector<double> change,
    double amount, unsigned int index)
{
    double current = 0.0;
    unsigned long long combinations = 0;

    if (amount == 0.0)
    {
        if (change.size() % 2 == 0)
        {
            combinations = Calculate(change);
        }
        return combinations;
    }

    // If amount is less than 0 then no solution exists
    if (amount < 0.0)
        return 0;

    // If there are no coins and index is greater than 0, then no solution exist
    if (index >= denominations.size())
        return 0;

    std::string str = std::to_string(amount) + "-" + std::to_string(index) + "-" + std::to_string(change.size());

    auto it = Memo.find(str);

    if (it != Memo.end())
    {
        return it->second;
    }

    while (current <= amount)
    {
        double remainder = amount - current;
        combinations += CalculateCombinations(denominations, change, remainder, index + 1);
        current += denominations[index];
        change.push_back(denominations[index]);
    }

    Memo[str] = combinations;
    return combinations;
}

有什么想法可以做到这一点吗?我知道有解决硬币更换问题的DP解决方案,但我的解决方案并不容易。我可以有半个便士。

*更新:我将函数改为迭代函数,并将其放大2倍以使用整数,但没有太大差别。

这是我的新代码:

unsigned long long CalculateCombinations(std::vector<int> &denominations, std::vector<int> change, int amount, unsigned int index)
{
    unsigned long long combinations = 0;

    if (amount <= 0)
        return combinations;

    std::stack<Param> mystack;
    mystack.push({ change, amount, index });

    while (!mystack.empty())
    {
        int current = 0;
        std::vector<int> current_coins = mystack.top().Coins;
        int current_amount = mystack.top().Amount;
        unsigned int current_index = mystack.top().Index;
        mystack.pop();

        if (current_amount == 0)
        {
            if (current_coins.size() % 2 == 0)
            {
                combinations += Calculate(std::move(current_coins));
            }
        }
        else
        {
            std::string str = std::to_string(current_amount) + "-" + std::to_string(current_index);
            if (Memo.find(str) == Memo.end())
            {
                // If amount is less than 0 then no solution exists
                if (current_amount >= 0 && current_index < denominations.size())
                {
                    while (current <= current_amount)
                    {
                        int remainder = current_amount - current;
                        mystack.push({ current_coins, remainder, current_index + 1 });
                        current += denominations[current_index];
                        current_coins.push_back(denominations[current_index]);
                    }
                }
                else
                {
                    Memo.insert(str);
                }
            }
        }
    }

    return combinations;
}

备忘录定义为std::unordered_set。

这能通过DP解决吗?问题是我对所有的组合都不感兴趣——只对大小均匀的组合感兴趣。

共有1个答案

漆雕深
2023-03-14

我在你的代码中没有看到任何丢弃面额的策略。

我的递归答案是在每个递归阶段创建2个子项:
1个子项使用面额的完整列表,并花费1个结束面额
第二个子项丢弃相同的结束面额

它们都会反复出现,但在第二种情况下,孩子们要处理的教派少了一个。

我相信返回的结果都是不同的,但当然你会遇到痛苦的情况,你递归10000级深,得到100美元的便士。这可以很容易地优化,当你得到了一个面额,并可能表明它是最好的处理和丢弃较高的面额在每一轮,而不是较低的面额。

您还可以检测到所有剩余面额都是彼此的简单倍数的情况,并在不进行完全递归的情况下快速生成排列:生成最小硬币集(每个高面额的最大值),然后反向将每个硬币替换为数量较小的硬币。

 类似资料:
  • 问题内容: 是否每个递归函数都有一个等效的for循环?(两者都达到相同的结果)。 我有这个递归函数: 假设单词是Set [],并且单词[i] =单词长度为i的集合。 我想做的是:使用一个单词(例如,“ stackoverflow”,没有空格)启动递归,我试图查找该单词是否可以切成子单词(“ stack”,“ over”,“ flow”) ..子词的最小长度为3,并且假设长度为i的子词在Set wo

  • 我们正在获取具有以下字段的订单数据(仅显示相关字段) 具有NULLoriginal_orderid的订单可以被认为是父订单 其中一些父母订单可能有子订单,子订单的original_orderid映射到父母的订单。 子顺序可以产生另一个子顺序,如图像所示,带有颜色编码。 与原始文本相同的数据: 作为转换,我们需要将所有子节点映射到它们的原始父节点(original_orderid为NULL),并获得

  • 我试图用递归的方法解决硬币兑换问题。问题是这样的: 你会得到不同面额的硬币和总金额。编写一个函数来计算组成该数量的组合数。 您将获得一个数量和一组硬币。 这是我到目前为止所拥有的: 当我这样做的时候,我没有得到任何接近正确的组合。我认为问题是回报,但我不明白为什么。在这里,我把硬币从数量中减去,每次都加在一起。当它得到0时,它返回1。

  • 我有一个关于如何将“递归”转换为“尾部递归”的问题。 这不是家庭作业,只是在我试图润色算法书籍中的递归定理时出现的一个问题。 我熟悉使用递归的两个典型示例(阶乘和斐波那契序列),也知道如何以递归方式和尾部递归方式实现它们。 我的代码如下(我使用Perl只是为了使其简单,但可以轻松地转换为C/Java/C)。 运行代码时,输出如下: 递归函数在返回之前使用不同的参数调用自己两次。我尝试了几种方法将其

  • 我需要在 ML 中编写自己的递归函数,该函数以某种方式使用 ord 将一串数字转换为整数类型。我可以使用辅助函数,但显然我应该能够在不使用辅助函数的情况下做到这一点(根据我的教授的说法)。 我可以假设输入是有效的,并且是一个正整数(当然是字符串类型)。 因此,调用str2int("1234")应该输出1234: int 我假设我需要在某个时候使用爆炸和内爆,因为 ord 对字符进行操作,而我的输入

  • 我想知道是否有一些通用方法可以用foo(…)转换“正常”递归foo(…) 作为尾部递归的最后一个调用。 例如(scala): 函数语言将递归函数转换为等价尾部调用的一般解决方案: 一种简单的方法是将非尾部递归函数包装在蹦床单子中。 所以pascal函数不再是递归函数。然而,蹦床单子是需要完成的计算的嵌套结构。最后,是一个尾递归函数,它遍历树状结构,解释它,最后在基本情况下返回值。 Rúnar Bj