简体   繁体   English

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

[英]Find all subarray with sum equal to number?

Could you please tell me how to find all subarray with sum equal to number Example你能告诉我如何找到总和等于数字的所有子数组吗示例

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

Or或者

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

I tried like that but not getting correct output我试过这样但没有得到正确的输出

 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));

for this expected output is对于这个预期的输出是

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

output: [1,3]
     [4]

expected output [[1,3], [4]] is my expected output预期输出 [[1,3], [4]] 是我的预期输出

You could iterate the array and take either the next element or if no element is taken before omit this element. 您可以迭代数组并采用下一个元素,或者如果在省略该元素之前未采用任何元素。

 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] 

This might not be exactly what's needed - might require tweaking as the logic may be flawed here. 这可能不完全是需要的-可能需要进行调整,因为此处的逻辑可能存在缺陷。

I have commented the code for clarification. 我已对代码进行注释以进行澄清。

 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 

This will try every possible permutation of the array (will stop further permutations once limit is reached) 这将尝试数组的所有可能排列(一旦达到限制,将停止进一步排列)

 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] 

If you want to make it more efficient and just return one of the resulted array just comment out the recursive call. 如果要提高效率,只需返回结果数组之一,只需注释掉递归调用即可。 You can also un-comment the line that exits the loop once the limit has been reached (will skip 0s). 一旦达到限制,您也可以取消注释退出循环的行(将跳过0)。

It will give all the available case. 它将给出所有可用的情况。 And I use the test case of @Nina Scholz 我使用@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] 

If the question is about finding all subsets (rather than subarrays) with the given cross sum it is also known as the perfect sum problem. 如果问题是要查找具有给定交叉和的所有子集(而不是子数组),则也称为完美和问题。 https://www.geeksforgeeks.org/perfect-sum-problem-print-subsets-given-sum/ https://www.geeksforgeeks.org/perfect-sum-problem-print-subsets-given-sum/


// A recursive function to print all subsets with the 
// help of dp[][]. Vector p[] stores current subset. 
function printSubsetsRec(arr, i, sum, p) 
{ 
    // If we reached end and sum is non-zero. We print 
    // p[] only if arr[0] is equal to sun OR dp[0][sum] 
    // is true. 
    if (i == 0 && sum != 0 && dp[0][sum]) 
    { 
        p.push(arr[i]); 
        console.log(p); 
        return; 
    } 

    // If sum becomes 0 
    if (i == 0 && sum == 0) 
    { 
        console.log(p); 
        return; 
    } 

    // If given sum can be achieved after ignoring 
    // current element. 
    if (dp[i-1][sum]) 
    { 
        // Create a new vector to store path 
        var b = p.slice(0); 
        printSubsetsRec(arr, i-1, sum, b); 
    } 

    // If given sum can be achieved after considering 
    // current element. 
    if (sum >= arr[i] && dp[i-1][sum-arr[i]]) 
    { 
        p.push(arr[i]); 
        printSubsetsRec(arr, i-1, sum-arr[i], p); 
    } 
} 

// Prints all subsets of arr[0..n-1] with sum 0. 
function printAllSubsets(arr, sum) 
{ 
    var n = arr.length
    if (n == 0 || sum < 0) 
       return; 

    // Sum 0 can always be achieved with 0 elements 
    dp = []; 
    for (var i=0; i<n; ++i) 
    { 
        dp[i] = []
        dp[i][0] = true; 
    } 

    // Sum arr[0] can be achieved with single element 
    if (arr[0] <= sum) 
       dp[0][arr[0]] = true; 

    // Fill rest of the entries in dp[][] 
    for (var i = 1; i < n; ++i) 
        for (var j = 0; j < sum + 1; ++j) 
            dp[i][j] = (arr[i] <= j) ? dp[i-1][j] || 
                                       dp[i-1][j-arr[i]] 
                                     : dp[i - 1][j]; 
    if (dp[n-1][sum] == false) 
    { 
        console.log("There are no subsets with sum %d\n", sum); 
        return; 
    } 

    // Now recursively traverse dp[][] to find all 
    // paths from dp[n-1][sum] 
    var p = []; 
    printSubsetsRec(arr, n-1, sum, p); 
} 

printAllSubsets([1,2,3,4,5], 10); 

Solution

'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);
      }
    }

  }
}

I would first loop depending on the size of expected arrays. 我将首先根据预期数组的大小进行循环。

After that loop for looking for first part of the array which should be filled with positions that will match the desired number. 在该循环之后,查找数组的第一部分,该部分的第一部分应与所需数字匹配。

For example for x= 4 having arr=[5,4,32,8,2,1,2,2,3,4,4] It would first take the 4's. 例如,对于具有arr = [5,4,32,8,2,1,2,2,3,4,4]的x = 4,它将首先取4。 Output will start on [ [4], [4], [4], ..... ] for positions 1,9,10 (respectively) 输出将分别从位置[1,9,10]的[[4],[4],[4],....]开始

Then go for the arrays resulting sum of 2 elements [ ... [2,2], [2,2],[2,2], [1,3] ...] ( positions 4+6, position 4+7 position6+7 and position 5+8) You would probably want to use another function to sum and check at this point. 然后对结果为2个元素[... [2,2],[2,2],[2,2],[1,3] ...]的数组求和(位置4 + 6,位置4+ 7 position6 + 7和position 5 + 8)此时您可能想要使用另一个函数进行求和和检查。

Now will do the same for sum of 3 elements (if any) and so on, having max loop set at number of original array (the resulting number could be the sum of all the elements in the array). 现在将对3个元素的总和(如果有的话)执行相同的操作,依此类推,将max循环设置为原始数组的数量(结果数量可能是数组中所有元素的总和)。

The resulting example would be [ [4], [4], [4], [2,2], [2,2],[2,2], [1,3]] 结果示例将是[[4],[4],[4],[2,2],[2,2],[2,2],[1,3]]


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 )

output 输出

[[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 )

output 输出

[[280],[0,280]]

If the elements would be strictly positive, one could collect such subsequences in a single pass, progressing in a worm/caterpillar-like way: stretching its front in order to grow the sum (when it is bellow the target) and contracting its back in order to lower the sum: 如果这些元素严格意义上是积极的,则可以一次收集此类子序列,并以蠕虫/毛毛虫般的方式前进:伸展其前端以增加总和(当它在目标以下时)并向后收缩为了降低总和:

 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)); 

One way to deal with the problem related to bounding zeroes is to throw such sequences away. 解决与边界零相关的问题的一种方法是丢弃此类序列。 This snippet keeps tail and head(-1) on non-zero elements: 此代码段将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)); 

And the code loses all of its remaining beauty if someone actually needs those 0+... / ...+0 sequences, as they have to be generated in a post-processing step: 如果有人确实需要这些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)); 

I think it works (for non-negative elements), but the first one was simpler for sure. 我认为它适用于(非负元素),但是第一个肯定更简单。

With map and filter带地图和过滤器

 const arr = [2, 4, 45, 6, 0, 19] let t = 0 const result = arr.map((v,i)=>{ return [v, t += v] }).filter((v,i)=>v[1]<=51) console.log(result)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM