检查数组中可能的值组合是否存在,并将其与给定值相加

时间:2016-01-19 05:09:47

标签: javascript arrays

FOR MODERATOR:

这个被认为是重复的问题,并没有解决许多问题。

  1. 这个问题不是关于运营商本身的工作方式,而是如何运作 它们在算法中起作用,即为什么那些操作员在那时。
  2. 这个问题还包括逐位比较'&'运营商,其中 其他问题根本没有解决。
  3. 所提供答案的核心见解是通过分配
    combinationsCount = 1 << listSize一个在循环中转动迭代器'i' 到一个位向量,可以针对特定的'j'进行测试来确定 如果它应该包含在要测试的总和中。
  4. 我认为,这是解决硬币变化问题的一种解决方案。据我所知,代码是有效的,但是我不明白最后一次检查是怎么回事:

    if (i & (1 << j)) {
        combinationSum += arr[j];
    }
    

    适用于此算法(见下文)。我遇到了一个教程。我非常感谢有关代码部分如何工作的任何解释。

    更新

    要清楚,我理解运算符正在做的 WHAT ,即位移和逐位加法。我想知道的是它们如何在算法中运作。

    possibleCombinationSumN(arr, n) {
      if (arr.indexOf(n) >= 0) {
        return true;
      }
    
      if (arr[0] > n) {
        return false;
      }
    
      if (arr[arr.length - 1] > n) {
        arr.pop();
        return possibleCombinationSumN(arr, n);
      }
    
      var listSize = arr.length, combinationsCount = (1 << listSize)
      for (var i = 1; i < combinationsCount; i++) {
        var combinationSum = 0;
        for (var j = 0; j < listSize; j++) {
          if (i & (1 << j)) {
            combinationSum += arr[j];
          }
        }
        if (n === combinationSum) {
          return true;
        }
      }
      return false;
    };
    

1 个答案:

答案 0 :(得分:2)

i用作位向量(零和一行),用于打开或关闭相应数组值在总和中的参与。

例如,如果arr有4个元素,则i11时,其二进制表示为0b1011;这表明我们应该总结arr[3] + arr[1] + arr[0],并省略arr[2]

现在 - 对于四元素数组,i将从0转到15。为什么?由于1 << arr.length是二进制0b100000b1向左移动了四个位置)或16,因此我们循环到其下方。这给出了0b00000b1111之间的二进制值 - 即四个1和0的所有可能组合。如果我们总结相应的数组值,我们将测试所有可能的总和组合。

i & (1 << j)测试j位是1

j3i为上述110b1011)。 1 << j0b1000; 0b1011 & 0b10000b1000,这是真实的。位于3的位置为arr[3],而combinationSum位于j

21 << j0b100b1011 & 0b100; 0b02,这是假的。位置arr[2]处为零; if __name__ == '__main__': g = Gui() g.start() 没有得到总结。