javascript 求唯一数字对的所有索引之和的最小值

li9yvcax  于 2023-01-01  发布在  Java
关注(0)|答案(5)|浏览(162)

我想循环遍历一个数组,然后把每个值相加,(除了它自己+它自己),如果循环遍历的两个值之和等于函数中的第二个参数,并且这对值之前没有遇到过,那么记住它们的索引,最后,返回所有记住的索引的总和。
换句话说,问题陈述是:给定整数数组
A
和作为所需总和的第二值s,从数组A的索引ij处查找所有值对,使得i〈jA [i]+ A [j]= s,并返回这些对的所有索引的总和,具有以下限制:

  • 不重用值对,即如果找到满足上述条件的两个索引对ijkl,并且如果A [i]== A [k]A [j]== A [l]A [i]== A [l]A [j]== A [k],则忽略具有较高索引和的对。
    • 示例**

例如,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
    • 示例2**

functionName([1, 3, 2, 4], 4)将仅等于1,因为仅前两个元素可配对为等于4,且第一元素具有索引0且第二元素具有索引1
这是我目前掌握的情况:

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

我的问题是,这一切都工作,但我有一个问题,一旦它找到一对等于第二个参数,那么它不应该使用相同的值对再次,但我这样做,例如:
如果数组是[1,1,1],第二个参数是2,循环将遍历并找到答案,但在找到和后继续搜索,我只希望它使用对[1, 1]一次,所以如果它在索引[0, 1]处找到这样的对,那么它不应该包括任何其他包含值1的对。
我在想,我可以删除其余的值是相同的,如果超过2个被发现使用过滤器留给我只有2个相同的值,如果有在一个数组,从而不必担心循环找到一个1 + 1两次,但这是最好的方式去做吗?
我还是新手,但期待您的意见

    • PS***我计划使用纯JavaScript完成此操作,不使用库 *

链接到一个JS小提琴,可能会使事情更容易看到我有什么。https://jsfiddle.net/ToreanJoel/xmumv3qt/

ffx8fchx

ffx8fchx1#

这比看起来要复杂得多,实际上,在循环中做循环会导致算法的时间复杂度与数组的大小成二次方关系,换句话说,对于大数组,要花很长时间才能完成。
处理此问题的另一种方法是注意数组中的每个唯一值实际上只需要使用一次(或者两次,如果s是偶数,并且数组中有两个s/2值)。否则,您将拥有非唯一对。这是因为如果您需要数字对xy,使得x + y = s,如果你知道x,那么y是确定的--它必须等于s-x
因此,你实际上可以用线性时间复杂度来解决这个问题(公平地说,如果A中的所有值都是唯一的,那么有时会是n*log(n),因为我们必须对它们排序一次)。
该算法的步骤如下:
1.创建一个Map,其键是数组A中的值,值是这些值在A中出现的索引的排序列表。
1.按升序浏览A中的所有唯一值(您在求解步骤1时收集了这些值)。对于每个此类值:
1.假设它是搜索的值对中较低的值。
1.计算较高值(等于s - lower
1.检查A中是否也存在更高的值(由于步骤1中创建的Map,您在恒定时间内执行此操作)。
1.如果是,则将较低值和较高值的最低索引添加到结果中。
1.返回结果。
下面是完整的代码:

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
9vw9lbht

9vw9lbht2#

这是可行的,但是会弄乱初始数组。

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

xkrw2x1b3#

如果找到了和,则使用循环重新开始求解。找到的被加数存储在usedNumbers中,稍后排序并用于获取索引,以便对索引求和。
排序和最后一个indexArray.prototype.indexOf提供了正确的起始位置。
编辑:
那么[1,1,1,1],2 ...应该是6还是1?-Jaromanda X 21
@JaromandaX应该为1,在找到具有这些值的对之后,它不应该再次查找具有相同值的对-Torean
此版本满足了此要求。

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
avwztpqn

avwztpqn4#

下面的解决方案非常简洁。它避免了不必要的检查,并且只在相关元素之间循环。您可以在这里检查工作代码: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
    • 引擎盖下:**

1.从index(i)= 0的元素开始循环。
1.只为数组中后面的元素添加第二个循环。它们的索引j总是高于i,因为我们在i上加1。
1.如果两个元素(数字)都小于或等于arg,则检查它们的和是否等于arg。这样就避免了检查其中一个数字大于arg时的和。
1.如果已找到该对,则将其值更改为NaN以避免进一步检查和重复。

w3nuxt5m

w3nuxt5m5#

这个解的时间复杂度应该是0(n)或线性的,比两个嵌套的for循环要快得多,这个函数会给你两个索引之和就是目标数,它可以很容易地被修改来解决这个问题的任何其他配置。

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

在Python中:

def twoSum(self, nums: List[int], target: int) -> List[int]:
        myMap = {}
        for i in range(len(nums)):
            myMap[nums[i]] = i
        for j in range(len(nums)):
            numToFind = target - nums[j]
            if numToFind in myMap and myMap[numToFind] != j:
                return [myMap[numToFind], j]

      print(twoSum([1,2,3,5,7], 5))

在Java中:

import java.util.*;

class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map<Integer, Integer> map = new HashMap<>();

        for(Integer i = 0; i < nums.length; i++) {
            map.put(nums[i], i);
        }

        for(Integer j = 0; j < nums.length; j++) {
            Integer numToFind = target - nums[j];

            Integer myInt = map.get(numToFind);
            if(map.containsKey(numToFind) && myInt != j) {
                return new int[] {myInt , j};
            }
        }
        
        return new int[] {0, 0};
    }
}

System.out.println(twoSum([1,2,3,5,7], 5))

相关问题