查找总和等于数字的所有子数组?

时间:2019-03-22 09:16:59

标签: javascript

能否请您告诉我如何找到总和等于数字的所有子数组 例子

arr[] = [2, 4, 45, 6, 0, 19]
   x  =  51
Output: [2,4,45]

arr[] = [1, 11, 100, 1, 0, 200, 3, 2, 1, 280]
    x = 280
Output: [280]

我试图那样,但是没有得到正确的输出

function getSubArray(arr, num) {
  var sum = 0,
    blank = [];
  var bigArr = []
  for (var i = 0; i < arr.length; i++) {
    sum = arr[i];
    if (blank.length === 0) {
      blank.push(arr[i]);
    }
    for (var j = 1; i < arr.length; j++) {
      sum += arr[j];
      if (sum < num) {
        blank.push(arr[j])
      } else if (sum > num) {
        sum = 0;
        blank = [];
        break;
      } else {
        blank.push(arr[j])
        bigArr.push(blank);
        sum = 0;
        blank = [];
      }
    }
  }

  return bigArr
}

console.log(getSubArray([1, 3, 6, 11, 1, 5, 4], 4));

此预期输出为

console.log(getSubArray([1, 3, 6, 11, 1, 5,4],4));

output: [1,3]
     [4]

预期输出 [[1,3],[4]]是我的预期输出

9 个答案:

答案 0 :(得分:5)

您可以迭代数组并获取下一个元素,或者在省略该元素之前不获取任何元素。

function getSubset(array, sum) {
    function iter(temp, delta, index) {
        if (!delta) result.push(temp);
        if (index >= array.length) return;
        iter(temp.concat(array[index]), delta - array[index], index + 1);
        if (!temp.length) iter(temp, delta, index + 1);
    }

    var result = [];
    iter([], sum, 0);
    return result;
}

console.log(getSubset([2, 4, 45, 6, 0, 19], 51));                   // [2, 4, 45], [45, 6], [45, 6, 0]
console.log(getSubset([1, 11, 100, 1, 0, 200, 3, 2, 1, 280], 280)); // [280]
console.log(getSubset([1, 3, 6, 11, 1, 5, 4], 4));                  // [1, 3], [4]

答案 1 :(得分:2)

这可能不完全是必需的-可能需要进行调整,因为此处的逻辑可能有缺陷。

我已经注释了代码以进行澄清。

var arr = [1, 3, 6, 11, 1, 5,4];	//  Define array

var target = 31;	//  Define target

//  filter the numbers higher than target and sort rest ascending
var withinRange = arr.filter(x => x <= target).sort((a, b) => a - b);
                      
if(arr.reduce((a,b) => a + b) < target)	//  Check if we have enough numbers to make up that number
  throw "The max you can get out of your selection is: " + arr.reduce((a,b) => a + b);
                      
//  grab the highest number as a starting point and remove it from our array of numbers
var numbers = [withinRange.pop()];

var toFind = target - getSum();	//  get remainder to find

for(var i = withinRange.length - 1; i > -1; i--)	//  iterate from the top
{

  if(toFind == withinRange[i]){	//  check if number is exactly what we need
    numbers.push(withinRange[i]);
    break;
  }else if(withinRange[i] <= toFind){	//  if number is smaller than what we look for
    numbers.push(withinRange[i]);
    toFind -= withinRange[i];
  }

}

function getSum(){	//  sum up our found numbers
  if(numbers.length == 0) return 0;
  return numbers.reduce((a,b) => a + b);
}

console.log([numbers, [target]]);	//  print numbers as desired output
console.log(target, getSum())	//  print the target and our numbers

答案 2 :(得分:1)

这将尝试数组的所有可能排列(一旦达到限制,将停止进一步排列)

function test(arr, num) {
  // sorting will improve time as larger values will be eliminated first
  arr = arr.sort(function(a, b) {
    return b - a;
  });
  var allLists = [];
  var start = Date.now();
  helper(0, 0, []);
  console.log("Ms elapesed: " + (Date.now() - start));
  return allLists || "Not found";

  function helper(start, total, list) {
    var result = [];
    // Using for loop is faster because you can start from desired index without using filter, slice, splice ...
    for (var index = start; index < arr.length; index++) {
      var item = arr[index];
      // If the total is too large the path can be skipped alltogether
      if (total + item <= num) {
        // Check lists if number was not included
        var test = helper(index + 1, total, list.concat(result)); // remove for efficiency
        total += item;
        result.push(item);
        //if (total === num) index = arr.length; add for efficiency
      }
    }
    if (total === num) allLists.push(list.concat(result));
  }
}



console.log(test([2, 4, 45, 6, 0, 19], 51)); // [2,4,45] [2,4,45,0] [6,45] [6,45,0]
console.log(test([1, 11, 100, 1, 0, 200, 3, 2, 1, 280], 280)); // [280] [280,0]

如果要提高效率,只需返回结果数组之一,只需注释掉递归调用即可。一旦达到限制,您也可以取消注释退出循环的行(将跳过0)。

答案 3 :(得分:1)

它将给出所有可用的情况。我使用@Nina Scholz的测试用例

const sum = arr => arr.reduce((a,b) => a + b)

function cal(arr, x) {
  const rs = []
  for (let i = 0; i< arr.length; i++) {
    const tmp = []
    for (let j=i; j<arr.length; j++ ) {
      tmp.push(arr[j])
      if(sum(tmp) === x) rs.push([...tmp])
    }
  }
  return rs
}


console.log(cal([1, 11, 100, 1, 0, 200, 3, 2, 1, 280], 280)) // -> [280]
console.log(cal([2, 4, 45, 6, 0, 19], 51)); // -> [2, 4, 45] [45, 6] [45, 6, 0]
console.log(cal([1, 3, 6, 11, 1, 5, 4], 4)); // -> [1,3] [4]

答案 4 :(得分:1)

如果问题在于查找具有给定交叉和的所有子集(而不是子数组),则也称为完美和问题。 https://www.geeksforgeeks.org/perfect-sum-problem-print-subsets-given-sum/

>>> df = pd.read_csv("/Users/SO/Desktop/test.csv",sep=';', decimal=",")
>>> df
       KG,
0  267.890
1  458.987
2  125.888
3    1.550
4    2.660
>>> 

答案 5 :(得分:0)

解决方案

'use strict';

function print(arr[], i, j) {
   let k = 0;
   for (k = i; k <= j; k += 1) {
     console.log(arr[k]);
   }
}

function findSubArrays(arr[], sum) {
  let n = arr.length;
  let i;
  let j;
  let sum_so_far;

  for (i = 0; i<n; i+= 1) {
    sum_so_far = 0;
    for (j = i; j < n; j++) {
      sum_so_far += arr[j];

      if (sum_so_far === sum) {
         print(arr, i, j);
      }
    }

  }
}

答案 6 :(得分:0)

我将首先根据预期数组的大小进行循环。

在该循环之后,查找数组的第一部分,该部分应填充与所需数字匹配的位置。

例如,对于x = 4且arr = [5,4,32,8,2,1,2,2,3,4,4] 首先要取4。输出将分别在位置[1,9,10]的[[4],[4],[4],....]上

然后对结果为2个元素[... [2,2],[2,2],[2,2],[1,3] ...](位置4 + 6,位置4 + 7位置6 + 7和位置5 + 8) 此时,您可能需要使用另一个函数进行求和并检查。

现在将对3个元素的总和(如果有)执行相同的操作,依此类推,将max循环设置为原始数组的数量(结果数量可能是数组中所有元素的总和)。

结果示例为[[4],[4],[4],[2,2],[2,2],[2,2],[1,3]]

答案 7 :(得分:0)


function combinations(array) {
    return new Array(1 << array.length).fill().map(
        (e1,i) => array.filter((e2, j) => i & 1 << j));
}

function add(acc,a) {
  return acc + a 
}

combinations([2, 4, 45, 6, 0, 19]).filter( subarray => subarray.reduce(add, 0)  == 51 )

输出

[[2,4,45],[45,6],[2,4,45,0],[45,6,0]]

combinations([1, 11, 100, 1, 0, 200, 3, 2, 1, 280]).filter( subarray => subarray.reduce(add, 0)  == 280 )

输出

[[280],[0,280]]

答案 8 :(得分:0)

如果这些元素严格意义上是正的,则可以一次收集此类子序列,并以蠕虫/毛虫的方式前进:伸展其前端以增加总和(当它是目标以下时)并收缩其后部以降低总和:

function worm(arr,target){
  var ret=[];
  var head=0;
  var tail=0;
  var sum=0;
  while(head<arr.length){
    while(sum<=target && head<arr.length){
      sum+=arr[head++];
      if(sum===target)
        ret.push(arr.slice(tail,head));
    }
    while(sum>=target && tail<head){
      sum-=arr[tail++];
      if(sum===target)
        ret.push(arr.slice(tail,head));
    }
  }
  return JSON.stringify(arr)+": "+JSON.stringify(ret);
}

console.log(worm([2, 4, 45, 6, 19], 51));
console.log(worm([1, 11, 100, 1, 200, 3, 2, 1, 280], 280));
console.log(worm([1, 3, 6, 11, 1, 5, 4], 4));

console.log("But it only occasionally finds 0+... / ...+0 sums:");
console.log(worm([2, 4, 45, 6, 0, 19], 51));
console.log(worm([2, 4, 0, 45, 0, 6, 0, 19], 51));
console.log(worm([0, 2, 4, 0, 45, 0, 6, 0, 19], 51));

处理与边界零相关的问题的一种方法是丢弃此类序列。此代码段将tailhead(-1)保留在非零元素上:

function worm(arr,target){
  var ret=[];
  var head=0;
  while(head<arr.length && arr[head]===0)head++;
  var tail=head;
  var sum=0;
  while(head<arr.length){
    while(sum<=target && head<arr.length){
      while(head<arr.length && arr[head]===0)head++;
      sum+=arr[head++];
      if(sum===target)
        ret.push(arr.slice(tail,head));
    }
    while(sum>=target && tail<head){
      sum-=arr[tail++];
      while(tail<head && arr[tail]===0)tail++;
      if(sum===target)
        ret.push(arr.slice(tail,head));
    }
  }
  return JSON.stringify(arr)+": "+JSON.stringify(ret);
}

console.log(worm([2, 4, 45, 6, 19], 51));
console.log(worm([1, 11, 100, 1, 200, 3, 2, 1, 280], 280));
console.log(worm([1, 3, 6, 11, 1, 5, 4], 4));
console.log(worm([2, 4, 45, 6, 0, 19], 51));
console.log(worm([2, 4, 0, 45, 0, 6, 0, 19], 51));
console.log(worm([0, 2, 4, 0, 45, 0, 6, 0, 19], 51));
console.log(worm([0, 2, 4, 0, 45, 0, 6, 0, 19, 26], 51));
console.log(worm([0, 2, 4, 0, 45, 0, 6, 0, 19, 26, 0], 51));
console.log(worm([1,8,2], 10));
console.log(worm([0,1,0,8,2,0], 10));
console.log(worm([0,8,2,8,0], 10));
console.log(worm([0,8,0,2,0,8,0], 10));

如果某人实际上需要这些0+... / ...+0序列,那么代码将失去所有剩余的美感,因为它们必须在后期处理步骤中生成:

function worm(arr,target){
  var pairs=[];
  var head=0;
  while(head<arr.length && arr[head]===0)head++;
  var tail=head;
  var sum=0;
  while(head<arr.length){
    while(sum<=target && head<arr.length){
      while(head<arr.length && arr[head]===0)head++;
      sum+=arr[head++];
      if(sum===target)
        pairs.push([tail,head]);
    }
    while(sum>=target && tail<head){
      sum-=arr[tail++];
      while(tail<head && arr[tail]===0)tail++;
      if(sum===target)
        pairs.push([tail,head]);
    }
  }
  var ret=[];
  for([tail,head] of pairs){
    (function pre(tail,head){
      ret.push(arr.slice(tail,head));
      if(tail>0 && arr[tail-1]===0)
        pre(tail-1,head);
      (function post(tail,head){
        if(head<arr.length && arr[head]===0){
          ret.push(arr.slice(tail,head+1));
          post(tail,head+1);
        }
      })(tail,head);
    })(tail,head);
  }
  return JSON.stringify(arr)+": "+JSON.stringify(ret);
}

console.log(worm([2, 4, 45, 6, 19], 51));
console.log(worm([1, 11, 100, 1, 200, 3, 2, 1, 280], 280));
console.log(worm([1, 3, 6, 11, 1, 5, 4], 4));
console.log(worm([2, 4, 45, 6, 0, 19], 51));
console.log(worm([2, 4, 0, 45, 0, 6, 0, 19], 51));
console.log(worm([0, 2, 4, 0, 45, 0, 6, 0, 19], 51));
console.log(worm([0, 2, 4, 0, 45, 0, 6, 0, 19, 26], 51));
console.log(worm([0, 2, 4, 0, 45, 0, 6, 0, 19, 26, 0], 51));
console.log(worm([1,8,2], 10));
console.log(worm([0,1,0,8,2,0], 10));
console.log(worm([0,8,2,8,0], 10));
console.log(worm([0,8,0,2,0,8,0], 10));

我认为它适用于(非负元素),但是第一个肯定更简单。