在一个数组中给定元素,找出相加等于目标值的组合。

3
我已经思考了相当长一段时间,但由于某种原因,这个问题仍然没有得到解决。如果我有一个数组[1,2,3,4]和一个目标值5,我想得到所有可能的组合,使它们加起来等于目标值。

所以我能想到的一种方法是:

1!=5
1+2!=5
1+3!=5
1+4=5
//now check with combos of 3 digits.
1+2+3 !=5
1+2+4 !=5
//now check with combos of 4...however at this point i realized i missed the combination 1+3+4 also.

我在网上看到了一些答案,但它们似乎没有意义,我也不太关心别人的答案或代码,我想学习如何正确思考以解决这些问题。我想知道是否有人可以指导我,帮助我分解这个问题,以及我应该如何思考来解决这些问题。此时我并不担心效率,因为我甚至还没有能够制定方法,所以所有方法都受欢迎。此外,我更喜欢使用数组和普通循环,而不是像哈希表这样的其他数据结构,因为我还没有学过它们。


4
您可能希望列举出原始数组的所有“子集”并检查其中哪些子集的总和为5。 - phimuemue
@phimuemue,你能详细说明一下吗?我不太确定你的意思。 - user1010101
也许这可以帮助你:https://dev59.com/vmMl5IYBdhLWcg3wkXlx - phimuemue
1
当处理这样的问题时,思考如何操作数据以使问题更容易解决也是有帮助的。例如,当数字数组按升序排序时,解决这个问题会更容易,而不是随机排序。递归在将大集合分成小集合的这类问题中也很有用。 - Dan Harms
@dcharms,是的,我会对数组进行排序,但我想知道你是否可以将递归方法分解一下,因为我有点理解不了。 - user1010101
显示剩余2条评论
1个回答

1
"由于您说您想要“思考方式”,这是一种方法。您可以从最简单的情况开始,做出各种假设: 1) 假设所有数组元素都小于目标值-在实现时进行简单验证即可。 高层次步骤: 您需要找到一种获取数字的所有可能排列的方法。 然后将每个排列的元素相加并检查是否与“目标”匹配(这是更简单的任务)。 现在来到这里的主要挑战: 如何获得所有可能的排列? 解决方案: 让我们假设我们有一个单元素的数组:显然,解决方案是简单的:) 接下来,我们有一个具有两个元素的数组: 您确定数组的大小:2 您必须迭代此大小,因为您的组合将小于或等于此大小。 您的第一次迭代将具有值1。即。您正在寻找大小为一的组合。 这很简单:您一个一个地迭代数组。"
下一次迭代将寻找大小为2的组合。 由于迭代值(2)等于数组大小(2),因此您知道只有一种可能的情况。
现在让我们处理一个大小为3的数组:
对于大小为1的排列,您知道该怎么做。
对于大小为3的排列,您知道组合是什么。
对于大小为2的排列,您需要另一个迭代。您遍历数组,保留数组的当前元素并对大小为2的其余数组进行排列。
接下来,您遍历第二个和第三个元素,并对大小为(3-1 = 2)的其余数组进行排列。
--------------------------------更新----------------------------------------------
接下来让我们尝试一个有4个元素的数组 我们称之为A(4)
对于大小为1和大小为4的排列,这是显而易见的。
对于大小为3的排列,您将重复获得大小为2的排列的过程,以获得大小为3的数组。
您将保留一个元素,剩下一个大小为3的数组。 让我们称它为A(3)。
但要记住,您还需要大小为2的排列。通过应用相同的可重复组件,您可以从大小为3的数组本身确定所有大小为2的排列。这变成了一个递归调用。
因此,基本上您大部分时间都要做一件事情。
'如果您有一个大小为n的数组A(n),则需要迭代它,保持正在迭代的元素,然后您将拥有一个大小为n-1的数组A(n-1)'
然后再次进行递归调用。 并在粗体行中用n-1替换n
因此,本质上,您可以看到这正在变成一个递归问题。
这是解决此问题的一种思路。我希望我在解释思考过程时清楚明白。
------------------------------------------示例------------------------------------------
假设我们有一个数组{1,2,3,4,5}
我们的函数如下:
 function G (int[] array ) {
   Looping over array{ 
       remove array[index] from array
        you are left with restOfTheArray .// store it some where.
       then
          make a recursive call to G with restOfTheArray; 
     }
 }

循环的干预运行:

 Dry run 1:
  funtion G (Array (n ) ) {
    Looping over {1,2,3,4,5}{ 
        first value while looping is 1, remove it from the array;
        you have {2,3,4,5}.// store it some where.
       then
          make a recursive call to G with {2,3,4,5}
     }
 } 


  Dry run 2: 
funtion G (Array (n ) ) {
   Looping over {1,2,3,4,5}{ 
       second value while looping is 2, remove it from the array;
        you have {1,3,4,5}.// store it some where.
       then
          make a recursive call to G with {1,3,4,5}
     }
 }

现在让我们查看递归调用的演示:
  Dry Run 1.1
 funtion G (Array (n ) ) {
   Looping over {1,2,3,4,5}{ 
       First value while looping is 1, remove it from the array;
        you have {2,3,4,5}.// store it some where.
       then
          make a recursive call to G with {2,3,4,5}
     }
 }

 Dry Run 1.2 

 funtion G (Array (n ) ) {
   Looping over {2,3,4,5}{ 
       First value while looping is 2, remove it from the array;
        you have {3,4,5}.// store it some where.
       then
          make a recursive call to G with {3,4,5}
     }
 }

等等...


我不明白为什么你在开始时就做出假设,比如固定元素大小以及数组值小于目标值。 - user1010101
我修改了假设。基本上,关于假设的想法是,在开始解决问题时,有时候假设一些事情是个好主意,这样可以将注意力集中在问题的核心部分。解决它,然后逐个删除假设并修正解决方案。 - DolphinJava
np!所以我认为你的答案应该从解决方案方法中阅读...我仍然有点不清楚这是如何递归工作的。 - user1010101
我在答案中澄清了递归部分,请再次查看答案。 - DolphinJava
很抱歉,能否展示一些可视化内容吗?我有点迷失你所说的遍历数组大小的意思。 - user1010101
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接