三数和

三数和

算法专家——JavaScript

今天的问题是 三数和 它非常有趣。

我们得到一个输入数组和一个目标值,并被要求返回所有可能的组合,这些组合可以和我们的目标相加。

因此,如果给定 ([12, 3, 1, 2, -6, 5, -8, 6], 6) 作为参数,则返回值应该是

[[-8, 2, 6], [-8, 3, 5], [-6, 1, 5]]

并且注意这些在每个子数组和外部数组中都进行了排序(这为问题增加了一个非常酷的额外层)

让我们跳进去!

我的想法是,我需要测试输入数组中所有可能的组合,以确保我已经收集了所有可能的解决方案-

立即的 我想到“所有可能的组合……”这个短语,我想到了递归回溯。它非常适合这些场景。我之前已经写过几篇关于 JavaScript 回溯的文章,所以如果您需要复习一下,请随时查看这些文章。

我想解决这个问题的方法是在数组中创建三个数字的所有可能组合,检查它们的总和,然后保留那些总和我的目标数字的组合。

然后,我将对结果子数组进行排序并返回。

编码出来:

首先,这是我的基本大纲:

逐行 -

  • 设置解决方案数组
  • 设置递归辅助函数
  • 调用助手(填充解决方案数组)
  • 返回解决方案

现在我会思考需要做的事情,并在此过程中完成代码......

帮手

首先,我想开始构建我的递归助手,以便进行必要的回溯,以便我们可以探索每个可用的数字组合并根据 targetSum 检查它们的总和。

让我们从基本情况开始……

所以现在,如果我递归构建的数组(组合)都是 3 位数长并且它的总和等于目标总和,我将创建它的排序浅表副本并将其添加到我的解决方案数组中。然后我将返回以总结执行上下文。

接下来,在助手内部,我需要开始迭代我的输入数组并执行实际的“回溯”。有一个相对简单的模板,您最终会发现大多数递归回溯问题看起来像这样:

从第 13 行开始,这就是正在发生的事情-

  • 我正在检查我的数组长度是否小于 3,以消除任何无意义的调用,即——我们的解决方案永远不能超过 3,因此超出此范围构建是一种浪费。
  • 如果我们的长度小于 3,首先我要将数组中的下一个值添加到当前组合中。
  • 然后我将重新调用帮助程序,将该组合作为参数与下一个索引一起传递。从这里开始,新的执行上下文将打开,直到构建完整的组合。它的总和与目标总和匹配,它将被添加到解决方案数组中。
  • 现在,第 17 行是实际“回溯”发生的地方。当我删除这个值时,它允许我在此过程中尝试所有其他可能的组合。 *如果没有图表,这非常难以可视化,所以如果您有兴趣更清楚地理解它,请查看我以前的帖子 回溯 在 JavaScript 中。

为了了解回溯是什么样子,让我们看一下示例输入和辅助调用的结果循环。这就是我们的输入“arr”在每个执行上下文中的样子。

您可以看到回溯的地形。

注意我们立即建立到三位数限制的方式,然后数组中的每个后续值都尝试在第三位数。

完成后,只有一个解决方案符合我们的标准(目标数 = 6)

完成

对于这个问题,我们几乎找到了一个可行的解决方案,只是现在我们返回的解决方案不仅需要在子数组级别上进行排序,而且还需要在整体上进行排序。

为此,我想尝试一个详细的解决方案并构建我自己的比较器函数。

我将首先为解决方案数组设置一个基本排序:

在第 23 行,我将解决方案重新定义为自身的排序版本,并且在排序代码块中我已经建立了条件来确定排序。

在这一点上,无疑有一种更简洁的方法可以做到这一点,但为了好玩,我宁愿创建一个辅助函数来评估两个子数组(a 或 b)中的哪一个是两者中的“较小”。

换句话说,给定两个子数组 -

[2, 5, 3] 和 [2, 3, 5]

[2, 3, 5] 应该在 [2, 5, 3] 之前

所以我将创建一个辅助函数来接收两个数组,比较它们并返回一个布尔值,指示我们正在寻找的顺序......

(完整解决方案)

现在,在第 33 行,我有一个助手,它将比较两个数组并指示第一个数组是否是较小的数组,是否应该在排序结果数组中排在第一位。

呸!

这是一个很好的问题,也是回溯的一个很好的介绍,但老实说,即使已经研究了一段时间,我也不希望能够在没有帮助的情况下完成这个。

我现在进入中等难度领域,所以这应该会继续提供一些巨大的挑战!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明

本文链接:https://www.qanswer.top/2872/16053108

posted @ 2022-08-31 08:16  哈哈哈来了啊啊啊  阅读(40)  评论(0编辑  收藏  举报