三数和
三数和
算法专家——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 版权协议,转载请附上原文出处链接和本声明