数组内n个数字的总和为x个数字并创建结果子集

时间:2019-05-14 15:04:27

标签: javascript node.js algorithm data-structures

例如,如果您有一个数组[20、6、7、8、50],并且如果我传递值21,则它应该返回[6,7,8]此子数组。注意:数字的总和应按顺序。

[20, 6, 7, 8, 50]
21 - [6, 7, 8]
13 - [6, 7]
50 - [] - because it is not in sequence

我尝试了但没用

function sumoftwonumer(arr, s) {
    let hashtable = {}
    let sum = []
    for(let i=0; i<arr.length; i++) {
        let innerRequiredValue = s - arr[i] 
        if(hashtable[innerRequiredValue.toString()] !== undefined) {
            sum.push([arr[i], innerRequiredValue])
        }
        hashtable[innerRequiredValue.toString()] = arr[i]
    }
    console.log(hashtable)
    return sum
}

2 个答案:

答案 0 :(得分:2)

您可以尝试使用嵌套的for循环。最坏情况下的时间复杂度为O(n^2)。确保看到第二种方法更有效。

let arr = [20, 6, 7, 8, 50]

function findNums(arr,sum){
  let temp = 0;
  for(let i = 0;i<arr.length;i++){
    temp = arr[i];
    for(let j = i+1;j<arr.length;j++){
      temp += arr[j];
      if(temp === sum) return arr.slice(i,j+1);
      if(temp > sum) break;
    }
  }
  return [];
}

console.log(findNums(arr,21))
console.log(findNums(arr,13))
console.log(findNums(arr,50))

更好的解决方案是创建变量temp的方法。开始一个接一个地添加元素。当它大于给定的总和时,则从数组的开头删除该元素。

let arr = [20, 6, 7, 8, 50]

function findNums(arr,sum){
  let temp = arr[0];
  let low = 0;
  for(let i = 1;i<arr.length;i++){
    temp += arr[i];
    if(temp === sum) return arr.slice(low,i+1);
    while(temp > sum){
      temp -= arr[low]
      low++;
    }
  }
  return [];
}

console.log(findNums(arr,21))
console.log(findNums(arr,13))
console.log(findNums(arr,50))

对于负数

负数的问题在于,当temp(当前总和)大于给定总和时,我们无法从开始删除元素,因为在数组后可能会有如此负数,这可能使{{1 }}小于或等于

对于负数,您需要创建一个对象来跟踪已经计算出的子数组总和。

temp

答案 1 :(得分:1)

根据您的使用方式,一种可能性是按照尝试尝试的方式进行操作,并创建部分和的哈希表,然后返回一个函数,该函数将在该哈希表中查找您的值。在这里,我这样做了,使函数变成咖喱状,这样您就不必进行每次调用都为一组数字创建哈希图的所有工作。

初始呼叫为O(n^2),但后续呼叫仅为O(1)。如果要在同一组数字上搜索多个值,则此样式很有用。如果您只需要搜索一个值,那么像Maheer Ali的答案中的第二个那样的技术会更有效。

const range = (lo, hi) => [...Array (hi - lo) ]
  .map ( (_, i) => lo + i )
const sum = (nbrs) => 
  nbrs .reduce ( (a, b) => a + b, 0 )

const findSequentialSum = (nbrs) => {
  const subtotals = range (0, nbrs .length)
    .flatMap (
      i => range (i + 2, nbrs .length + 1)
        .map (j => nbrs .slice (i, j) )
    ) 
    // .reduce((a, b) => a.concat(b), [[]])
    .reduce ( 
      (a, sub, _, __, tot = sum(sub) ) => ({
        ...a, 
        [tot]: a [tot] || sub
      }),
      {}
    )
  return (total) => subtotals [total] || []
}

const nbrs = [20, 6, 7, 8, 50]

const search = findSequentialSum (nbrs)

console .log (
  search (21), //~> [6, 7, 8]
  search (13), //~> [6, 7]
  search (50), //~> []
)

这两个辅助函数应该很简单:range(3, 10) //=> [3, 4, 5, 6, 7, 8, 9]sum([2, 5, 10]) //=> 17

如果您的环境中有flatMap isn't available,则可以替换

    .flatMap (
      i => range (i + 2, nbrs .length + 1)
        .map (j => nbrs .slice (i, j) )
    ) 

使用

    .map (
      i => range (i + 2, nbrs .length + 1)
        .map (j => nbrs .slice (i, j) )
    ) 
    .reduce((a, b) => a.concat(b), [[]])

此外,这里的2

      i => range (i + 2, nbrs .length + 1)

要求序列的长度至少为两个。如果您想让50返回[50](对我来说似乎更合逻辑),那么您可以将2替换为1。或者,如果您只想查找长度为5或更大的子序列,则可以用更大的替换它。

最后,如果您想返回添加到总数中的 all 个子序列,则将是一个简单的修改,替换为:

        [tot]: a [tot] || sub

使用

        [tot]: (a [tot] || []).concat([sub])