递归收缩数组并将其作为新参数传递

时间:2017-01-28 18:13:47

标签: c# recursion

是否有可能继续消除数组的元素(即在处理第一个,第二个等时缩小它...)并将其作为新参数传递给同一个函数(即递归)?

我正在尝试提出一种计算客户更改所需的每个硬币数量的简单方法(例如在自动售货机中),但因为我对所有使用嵌套的Google搜索结果感到困惑循环等...(我的意思是我发现它们很难理解)我决定看看我是否可以将我的想法转化为一个简单的递归调用来解决这个问题。

到目前为止我所拥有的内容如下。我们假设机器应该返回80美分的变化,给出10,20,50,100和200个硬币的面额清单。一个人会想:第一枚硬币是" less"超过80是50美分,所以我需要一个50美分,现在剩下的是30美分。

小于30的第一个硬币是20美分,所以我需要一个20美分,现在剩下的只有10美分。小于(或在这种情况下等于)剩下的第一枚硬币是10美分,完成了这个过程。

所以,在每一步,在照顾到帮助我的最大硬币面额之后,我是"无视"其他大硬币太多了;也就是说,我正在删除对我无益的无用硬币面额。

现在,编写了我简单的思维方式,我想出了以下内容,现在我想知道如何映射这个"硬币面额阵列缩小"代码?在我放置temp数组...

的地方突出显示

我的意思是,当我开始时,我检查了2欧元硬币(200)coins[1]并且它太大了。所以coins[2]是1欧元。然后50美分硬币帮助(coins[3])这样排序,但现在我想在Calculatecoins[4]上运行相同的方法coins[5]被认为是一个新的axed数组,现在只包含索引4和5,可以继续解决问题。

这甚至可能吗?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace CoinsConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] coins = new int[5] { 200, 100, 50, 20, 10 };

            Calculate(coins, 80); // 50 + 20 + 10

            Console.ReadLine();
        }


        static []int Calculate(int[] coins, int change)
        {
            int[] counts = new int[5] { 0, 0, 0, 0, 0 };
            int remaining;

            for (int i = 1; i <= coins.Length; i++)
            {
                if (coins[i] <= change)
                {
                    remaining = change - coins[i];
                    ++counts[i];
                    []int temp = coins.Skip(i);
                    Calculate(temp, remaining);
                }
            }

            return counts;
        }
    }
}

编辑1:这不仅仅是array.Skip(n).Take(n)的副本。我试图了解如何传递修改后的数组进行递归;例如我是否应该使用array.Copy或相同的轴数等...

编辑2:我已经采用了我认为应该传递新缩短数组的方式,但是coins.Skip(i)Calculate(temp, remaining)都加下划线红色。我做错了什么?

3 个答案:

答案 0 :(得分:3)

通常通过为每次递归调用提取子数组来 not 。相反,它总是传递完全相同的数组,以及起始索引和要考虑的元素数。

通过这种方式,您不必参与提取子数组的繁琐业务,您的代码将表现得更好。

如果你不想改变方法的公共接口,那么让它调用一个内部(私有)方法,它完成所有工作(包括递归),将0传递给起始索引和数组.length为长度。

如果您坚持提取子数组,则必须自己分配,然后使用Array.Copy将旧数组中的一系列元素复制到新数组。见https://msdn.microsoft.com/en-us/library/system.array.copy(v=vs.110).aspx

答案 1 :(得分:1)

这并没有回答你的问题,但它可能会让你睁大眼睛看其他可能更简单的方法。

为什么你没有一堆硬币的分类容器?请考虑以下结构:Dictionary<int, Stack<Coin>>。这个容器将有一堆硬币按价值(以美分为单位)分类。

coins[10]将为您提供机器中所有10美分硬币的堆叠。 coins[25]会给你宿舍等等。

当客户添加硬币时,您只需放入适当的堆栈:coins[enteredCoin.Value].Push(enteredCoin)

这也使您可以轻松配置不同货币的自动售货机。在启动时,在字典中注册您要接受的硬币(钥匙)并为自动售货机预充电(新的堆叠和推动硬币)。

检查是否有任何输入的硬币也是可以接受的,只需检查该值是否是字典的有效密钥,如果不是,则将其返还给客户。

通过这种方法,事情变得更加容易。

答案 2 :(得分:1)

我发布了你的问题的答案,因为我担心其他答案可能有点太复杂,你无法跟随或给你一个错误的想法。

static void CalculateChange(int change, int[] coins)
{
    Console.Write(change + " = ");

    int j = 0;
    while (change > 0)
    {
        for (int i = j; i < coins.Length; i++)
        {
            int coin = coins[i];
            if (coin <= change)
            {
                change = change - coin;
                j = i; // remmeber the position of the biggest possible coin, to start from next loop
                Console.Write(coin + " ");
                break;
            }
        }
    }
}

如您所见,您非常接近。

这里的变量j是优化内部for循环。它简单地记住了最后一枚硬币的位置,因此它不需要再检查所有已经变大的硬币。

该程序仍然适用于j。我把它放在那里以适应你减少剩余硬币的想法。

需要注意两点:首先,此答案假设int[] coins按降序排序。其次,这是一种迭代方法,我相信你会计算出递归方法。