【问题标题】:Recursively merge two arrays, taking alternate elements (Java)递归合并两个数组,取交替元素(Java)
【发布时间】:2016-07-29 02:31:31
【问题描述】:

我真的需要帮助来解决家庭作业问题。几天来我一直在努力解决这个问题,非常感谢您的帮助!提示如下:

将两个数组合并为一个。编写一个名为 merge 的方法,它需要 3 个整数数组 参数:a、b 和 soln。 soln 保证为 a.length + b.length 的大小。数组 a 和 b 应该通过交替元素“合并”成一个数组。添加第 4 个参数,它指示对于给定的方法递归调用应该更新 soln 中的哪个元素。

例子:

merge({1, 2, 3}, {4, 5, 6}, soln, 0) 应该以 soln 中的以下值结尾:{1, 4, 2, 5, 3, 6}

merge({1,2}, {3,4,5}, soln, 0) 应以 soln 中的以下值结尾:{1,3,2,4,5}

我可以让它与长度相同的数组一起工作,即使数组的长度不同(但只有一个元素)。我无法让索引正确排列。我已经尝试了许多不同的变体,但到目前为止,这是我所拥有的:

public static void merge3(int[] a, int[] b, int[] soln, int index) {
    if (index > soln.length-1) {
        return; //if index reaches end of soln length
    }

        int index2 = (int)(index/2); //allows me to pull alternately from a and b arrays. As index goes up, index2 becomes 0, 0, 1, 1, 2, 2, etc.

        if (b.length >= a.length) {
            if (index%2 == 0) {
                if (index2 > a.length-1) {
                    soln[index] = b[index2];
                    merge3(a, b, soln, index+1);
                } else {
                    soln[index] = a[index2];
                    merge3(a, b, soln, index+1);
                }
            } else {
                soln[index] = b[index2];
                merge3(a, b, soln, index+1);
            }

        } else if (b.length < a.length) {
            if (index%2 == 0) {
                soln[index] = a[index2];
                merge3(a, b, soln, index+1);
            } else {
                if (index2 >= b.length) {
                    soln[index] = a[index2];
                    merge3(a, b, soln, index+1);
                } else {
                    soln[index] = b[index2];
                    merge3(a, b, soln, index+1);
                }
            }
        }
}

如果数组 a 是 {1, 2, 3},数组 b 是 {4, 5, 6, 7, 8, 9},则 soln 变为 {1, 4, 2, 5, 3, 6, 7, 7 , 8} 而不是应该是 {1, 4, 2, 5, 3, 6, 7, 8, 9}。它关闭了,因为当我执行 index + 1 时,递归调用捕获了相同的值 (index2),该值用于在只剩下一个数组时在数组之间交替。请帮忙!谢谢!

【问题讨论】:

  • 是否需要递归调用?
  • 鉴于这是作业;我的建议是写下如果你不得不用笔和纸来做这件事你会采取的步骤。这些将是您算法的步骤。
  • 是的,我们需要使用递归调用。而且我已经做到了(交替,然后用剩下的填写soln)——理论上我很难实现!我已经想出了如何递归合并。但是当数组的长度相差超过 1 时,我无法弄清楚如何从正确的索引中绘制。
  • 差异的大小应该是无关紧要的,如果它是 1 或 1000 则并不重要。您是否考虑过,一旦您点击了比其他数组更多的第一个元素,您只需从该元素复制到数组的末尾?
  • 是的,但我不知道如何递归地从头到尾复制元素。 :( 使用 for 循环会很容易!但是如果我必须再次调用递归方法,一切都会被我的索引弄乱。(顺便说一句,谢谢你的帮助!)

标签: java arrays recursion merge


【解决方案1】:

这是一种故意迂腐的方法来思考这类问题。

从确定你的状态开始。将这个问题中的所有可能性划分为不同状态的一种方法是:

  • 退出,您只需返回即可。 (对于每个递归调用的方法总是需要这个)。
  • 在数组耗尽之前,在每个输入数组ab 中仍然至少有一个数组元素。
  • 数组耗尽后,其中所有较小数组的元素都已添加到soln
  • array aempty 其中第一个数组没有元素。通常你会在递归调用之外处理这个问题,但我们在这里遵循规则......

这些状态中的每一个都代表您处理输入所需的不同方式。

这种结构的伪代码如下所示:

if (test to see if we're in "exit" state) {
    logic handling "exit" state
} else {
    if (test to see if we're in "before array exhaustion" state) {
        logic handling "before array exhaustion" state
    } else {
        if (test to see if we're in "array `a` empty" state ) {
            logic handling "array `a` empty" state
        } else {
            logic handling "after array exhaustion" state

        }

    }
}
recursive call to your method here

您已经在此处拥有(test to see if we're in "exit" state)

if (index > soln.length-1) {

你在这里有logic handling "exit" state

    return; //if index reaches end of soln length

由于这个状态的逻辑returns,语法不需要你像在伪代码中那样把它放在 if-else 中,但是当你处理 Java 语法时它可能会更清楚 if你始终使用 if-else 结构。
之后,您需要有条件的if (test to see if we're in "before array exhaustion" state),但您的代码假定您位于logic handling "before array exhaustion" state 并相应地处理它。逻辑是好的,但状态不是。您需要使用模板并将该逻辑放在适当的位置,但至少您不必重写它。

现在填写伪代码模板的其余部分,从测试开始。

测试:
test to see if we're in "array 'a' empty" state 只是查看数组 a 是否为空,因此编写起来非常简单。
test to see if we're in "before array exhaustion" state 根据 a.length、b.length 和 index 检查我们是否已经将所有较小数组的元素复制到了 soln 中。

数组填充逻辑:
你在退出案例下面的内容非常适合logic handling "before array exhaustion" state,所以你只需要写:

  • logic handling "array 'a' empty" state 你已经知道数组 a 是空的。
  • logic handling "after array exhaustion" state。这是我们完成较小数组的部分,我们需要知道从较大的输入数组中提取哪个元素,以便我们可以将其添加到 soln。

所以基本上按照模板编写 3 个测试(1 个已经完成,1 个微不足道,还有一个),然后为不同的状态编写逻辑(两个已经完成,一个微不足道,还有一个)然后你'在那里。

您还可以考虑重构现有代码,以便在最后只发生一次递归调用。这称为尾递归,即使 Java SE 8 具有所有优化,这种方式仍然更好。也干净了很多。

希望这是一个有用的模板来思考一个简单的问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-25
    • 1970-01-01
    • 2019-09-09
    相关资源
    最近更新 更多