简体   繁体   English

找到总和为给定数字的唯一数字对的所有索引的最小总和

[英]Find the smallest sum of all indexes of unique number pairs summing to a given number

I want to loop through an array and then add each value to each other (except itself + itself) and if the sum of the two values that were looped through equals the second argument in my function, and the pair of values hasn't been encountered before, then remember their indices and, at the end, return the full sum of all remembered indices.我想遍历一个数组,然后将每个值彼此相加(除了自身 + 自身) ,如果循环的两个值的总和等于我的 function 中的第二个参数,并且这对值还没有之前遇到过,然后记住它们的索引,最后返回所有记住的索引的总和。


In other words, the problem statement is: given an array A of integers and a second value s that is a desired sum, find all pairs of values from array A at indexes i , j such that i < j and A[i] + A[j] = s , and return the sum of all indexes of these pairs, with the following restriction:换句话说,问题陈述是:给定一个整数数组A和一个期望和的第二个值s ,从数组A中找到索引为ij的所有值对,使得i < jA[i] + A[j] = s ,并返回这些对的所有索引的总和,具有以下限制:

  • don't reuse value pairs, ie if two index pairs i , j and k , l satisfying the above conditions are found and if A[i] == A[k] and A[j] == A[l] or A[i] == A[l] and A[j] == A[k] , then ignore the pair with the higher index sum.不要重用值对,即如果找到满足上述条件的两个索引对i , jk , l并且如果A[i] == A[k]A[j] == A[l]A [i] == A[l]A[j] == A[k] ,然后忽略具有较高索引和的对。

Example例子

For example, functionName([1, 4, 2, 3, 0, 5], 7) should return 11 because values 4, 2, 3 and 5 can be paired with each other to equal 7 and the 11 comes from adding the indices of them to get to 11 where:例如, functionName([1, 4, 2, 3, 0, 5], 7)应该返回 11,因为值 4、2、3 和 5 可以相互配对等于 7,而 11 来自添加索引其中有 11 个是:

4 + 3 = 7 
5 + 2 = 7 

4 [index: 1]
2 [index: 2]
3 [index: 3]
5 [index: 5]

1 + 2 + 3 + 5 = 11

Example #2例子#2

functionName([1, 3, 2, 4], 4) would only equal 1, because only the first two elements can be paired to equal 4, and the first element has an index of 0 and the second 1 functionName([1, 3, 2, 4], 4)只会等于 1,因为只有前两个元素可以配对等于 4,并且第一个元素的索引为 0,第二个元素为 1

1 + 3 = 4

1 [index: 0]
3 [index: 1]

0 + 1 = 1

This is what I have so far:这是我到目前为止所拥有的:

function functionName(arr, arg) {
    var newArr = [];
    for(var i = 0; i < arr.length; i++){
        for(var j = i + 1; j < arr.length; j++) {
            if((arr[i] + arr[j]) === arg ) {
                newArr.push(i , j);
            }
        }
    }

    if(newArr.length === 0) {
        return console.log(0);
    }
    return console.log(newArr.reduce(function(a,b){return a + b}));
}

functionName([1, 4, 2, 3, 0, 5], 7);

The problem I have is that it all works but I have the issue that once it finds a pair that equals the second argument, then it's not supposed to use the same value pairs again but mine does, eg:我遇到的问题是它一切正常,但我有一个问题,一旦它找到一对等于第二个参数,那么它不应该再次使用相同的值对,但我的确实如此,例如:

if the array is [1,1,1] and the second argument is 2 , the loop will go through and find the answer but it continues to search after it finds the sum and I only want it to use the pair [1, 1] once, so if it finds a pair like this at indexes [0, 1] then it should not include any other pair that contains the value 1 .如果数组是[1,1,1]并且第二个参数是2 ,循环将通过 go 找到答案,但它在找到总和后继续搜索,我只希望它使用对[1, 1]一次,所以如果它在索引[0, 1]处找到这样的一对,那么它不应该包括任何其他包含值1的对。


I was thinking that i could remove the rest of the values that are the same if more than 2 are found using filter leaving me with only 2 of the same value if there is in an array thus not having to worry about the loop finding a 1 + 1 twice but is this the best way to go about doing it?我在想我可以删除 rest 相同的值,如果使用过滤器找到超过 2 个,如果数组中存在,我只剩下 2 个相同的值,因此不必担心循环找到 1 + 1 两次,但这是 go 的最佳方式吗?

I'm still new to this but looking forward to your comments我对此还很陌生,但期待您的评论

PS I'm planning on doing this using pure JavaScript and no libraries PS我打算使用纯 JavaScript 而不使用库来执行此操作

Link to a JS fiddle that might make things easier to see what I have.链接到一个 JS 小提琴,这可能会让我更容易看到我拥有的东西。 https://jsfiddle.net/ToreanJoel/xmumv3qt/ https://jsfiddle.net/ToreanJoel/xmumv3qt/

This is more complicated than it initially looks. 这比最初看起来要复杂。 In fact, making a loop inside a loop causes the algorithm to have quadratic time complexity with regard to the size of the array. 实际上,在循环内进行循环会导致算法在数组大小方面具有二次时间复杂度 In other words, for large arrays of numbers, it will take a very long time to complete. 换句话说,对于大量数字,将需要很长时间才能完成。

Another way to handle this problem is to notice that you actually have to use each unique value in the array only once (or twice, if s is even and you have two s/2 values somewhere in the array). 处理此问题的另一种方法是,您实际上必须只使用一次数组中的每个唯一值(如果s为偶数,并且在数组中的某个位置有两个s / 2值,则必须使用两次)。 Otherwise, you would have non-unique pairs. 否则,您将拥有非唯一的对。 This works because if you need pairs of numbers x and y such that x + y = s , if you know x , then y is determined -- it must be equal s - x . 之所以起作用,是因为如果您需要xy对成对,使得x + y = s ,如果您知道x ,那么就可以确定y -它必须等于s-x

So you can actually solve the problem in linear time complexity (to be fair, it's sometimes n*log(n) if all values in A are unique, because we have to sort them once). 因此,您实际上可以解决线性时间复杂度的问题(公平地说,如果A中的所有值都是唯一的,则有时为n*log(n) ,因为我们必须对它们进行一次排序)。

The steps of the algorithm are as follows: 该算法的步骤如下:

  1. Make a map whose keys are values in array A , and values are sorted lists of indexes these values appear at in A . 制作一个映射,其键为数组A中的值,并且值是索引的排序列表,这些值出现在A中
  2. Move through all unique values in A (you collected them when you solved step 1) in ascending order. 按升序移动A中的所有唯一值(在解决步骤1时收集的值)。 For each such value: 对于每个这样的值:
    1. Assume it's the lower value of the searched pair of values. 假设它是所搜索值对中的较低值。
    2. Calculate the higher value (it's equal to s - lower ) 计算较高的值(等于s - lower
    3. Check if the higher value also existed in A (you're doing it in constant time thanks to the map created in step 1). 检查A中是否还存在较高的值(由于在步骤1中创建了映射,您可以在恒定的时间内执行此操作)。
    4. If it does, add the lowest indexes of both the lower and the higher value to the result. 如果是这样,则将较低和较高值的最低索引添加到结果中。
  3. Return the result. 返回结果。

Here's the full code: 这是完整的代码:

 function findSumOfUniquePairs(numbers, sum) { // First, make a map from values to lists of indexes with this value: var indexesByValue = {}, values = []; numbers.forEach(function (value, index) { var indexes = indexesByValue[value]; if (!indexes) { indexes = indexesByValue[value] = []; values.push(value); } indexes.push(index); }); values.sort(); var result = 0; for (var i = 0, maxI = values.length; i < maxI; ++i) { var lowerValue = values[i], higherValue = sum - lowerValue; if (lowerValue > higherValue) { // We don't have to check symmetrical situations, so let's quit early: break; } var lowerValueIndexes = indexesByValue[lowerValue]; if (lowerValue === higherValue) { if (lowerValueIndexes.length >= 2) { result += lowerValueIndexes[0] + lowerValueIndexes[1]; } } else { var higherValueIndexes = indexesByValue[higherValue]; if (higherValueIndexes) { result += lowerValueIndexes[0] + higherValueIndexes[0]; } } } return result; } document.write(findSumOfUniquePairs([1, 4, 2, 3, 0, 5], 7) + '<br>'); // 11; document.write(findSumOfUniquePairs([1, 3, 2, 4], 4) + '<br>'); // 1 document.write(findSumOfUniquePairs([1, 1, 1], 2) + '<br>'); // 1 document.write(findSumOfUniquePairs([1, 1, 1, 1], 2) + '<br>'); // 1 document.write(findSumOfUniquePairs([1, 2, 3, 1, 2, 3, 1], 4) + '<br>'); // 7 document.write(findSumOfUniquePairs([5, 5, 1, 1, 1], 6) + '<br>'); // 2 document.write(findSumOfUniquePairs([0, 5, 0, 5, 1, 1, 1], 6) + '<br>'); // 5 

This works, but it mucks up the initial array. 这行得通,但它会掩盖初始数组。

function functionName(arr, arg) {
    var newArr = [];
    for(var i = 0; i < arr.length; i++){
        for(var j = i + 1; j < arr.length; j++) {
            if((arr[i] + arr[j]) === arg ) {
                newArr.push(i , j);
                arr[i] = null;
                arr[j] = null;
            }
        }
    }

    if(newArr.length === 0) {
        return console.log(0);
    }
    return console.log(newArr.reduce(function(a,b){return a + b}));
}

Solution with loops with restart, if a sum is found. 如果找到总和,则重新启动循环的解决方案。 the found summands are stored in usedNumbers and later sorted and used to get the index for summing the index. 找到的求和数存储在usedNumbers ,随后进行排序并用于获取索引以对索引求和。

The sorting and the last index provides the correct start position for the Array.prototype.indexOf . 排序和最后一个indexArray.prototype.indexOf提供了正确的开始位置。

Edit: 编辑:

what about [1,1,1,1], 2 ... should that be 6 or 1? 那么[1,1,1,1],2 ...应该是6还是1? – Jaromanda X 21 – Jaromanda X 21

@JaromandaX that should be 1, after the pair is found with the values then it shouldn't look for a pair with the same values again – Torean @JaromandaX应该为1,在找到具有值的对之后,就不应再寻找具有相同值的对– Torean

This version takes care of the requirement. 此版本可满足要求。

 function f(array, sum) { var arrayCopy = array.slice(0), usedNumbers = [], index = 0, indexA = 0, indexB, a, b; while (indexA < arrayCopy.length) { indexB = indexA + 1; while (indexB < arrayCopy.length) { a = arrayCopy[indexA]; b = arrayCopy[indexB]; if (a + b === sum) { usedNumbers.push(a, b); arrayCopy = arrayCopy.filter(function (i) { return a !== i && b !== i; }); indexA--; // correction to keep the index break; } indexB++; } indexA++; } return usedNumbers.sort().reduce(function (r, a, i) { index = array.indexOf(a, i === 0 || a !== usedNumbers[i - 1] ? 0 : index + 1); return r + index; }, 0); } document.write(f([1, 4, 2, 3, 0, 5], 7) + '<br>'); // 11 document.write(f([1, 1, 1], 2) + '<br>'); // 1 document.write(f([5, 5, 1, 1, 1], 6) + '<br>'); // 2 document.write(f([0, 5, 0, 5, 1, 1, 1], 6) + '<br>'); // 5 document.write(f([1, 1, 1, 1], 2) + '<br>'); // 1 

The solution below is very compact. 下面的解决方案非常紧凑。 It avoids unnecessary checks and loops only through the relevant elements. 它避免了不必要的检查,并且仅通过相关元素进行循环。 You can check the working codepen here: http://codepen.io/PiotrBerebecki/pen/RRGaBZ . 您可以在此处检查有效的Codepen: http ://codepen.io/PiotrBerebecki/pen/RRGaBZ。

function pairwise(arr, arg) {
  var sum = 0;
  for (var i=0; i<arr.length-1; i++) {
    for (var j=i+1; j<arr.length; j++) {
      if (arr[i] <= arg && arr[j] <= arg && arr[i] + arr[j] == arg) {
        sum += i+j; 
        arr[i] = arr[j] = NaN;
      }   
    }
  }
  return sum;
}

console.log(  pairwise([1, 1, 0, 2], 2)  ) // should return 6

Under the hood: 在引擎盖下:

  1. Start looping from the element with index ( i ) = 0. 从索引( i )= 0的元素开始循环。
  2. Add a second loop only for the elements which are later in the array. 仅为数组中后面的元素添加第二个循环。 Their index j is always higher than i as we are adding 1 to i . 它们的索引j总是比i高,因为我们要向i加1。
  3. If both elements (numbers) are less than or equal to to the arg , check if their sum equals to the arg . 如果两个元素(数字)均小于或等于arg ,请检查它们的总和是否等于arg This avoids checking the sum if either of the numbers are greater than the arg . 如果两个数字中的任何一个大于arg这都可以避免检查总和。
  4. If the pair has been found then change their values to NaN to avoid further checks and duplication. 如果找到了该对,则将其值更改为NaN以避免进一步检查和重复。

This solution should have a time complexity of 0(n) or linear Much faster than two nested for-loops.此解决方案的时间复杂度应为 0(n) 或线性 比两个嵌套的 for 循环快得多。 This function will give you the two indices that add up to the target number.这个 function 将为您提供加起来等于目标数字的两个索引。 It can easily be modified to solve any other configuration of this problem.可以很容易地修改它来解决这个问题的任何其他配置。

var twoSum = function(nums, target) {
    const hash = {}
    for(let i = 0; i < nums.length; i++) {
        hash[nums[i]] = i
    }
    for(let j = 0; j < nums.length; j++) {
        let numToFind = target - nums[j]
        if(numToFind in hash && hash[numToFind] !== j) {
            return [hash[numToFind], j]
        }
    }
    return false
};

console.log(twoSum([1,2,3,5,7], 5))

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

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