【问题标题】:Javascript twoSum algorithm: Given an array of integers, return indices of the two numbers such that they add up to a specific targetJavascript twoSum 算法:给定一个整数数组,返回两个数字的索引,使它们加起来为特定目标
【发布时间】:2019-12-23 23:10:28
【问题描述】:

给定一个整数数组,返回两个数字的索引,使它们相加到一个特定的目标。

示例:

给定 nums = [3, 2, 4],目标 = 6,

因为nums[1] + nums[2] = 2 + 4 = 6

return [1, 2].

解决方案

var twoSum = function(nums, target) {
    for(let i = 0; i <= nums.length; i++){
        for(let j = 0; j <= nums.length; j++){
            if(nums[i] + nums[j] == target){
                return [i, j]
            }
        }
    }
};

上面的代码在其他情况下有效,但不是这个。

预期结果 [1,2]

输出 [0,0]

例如,我尝试使用不同的数字数组和不同的目标,即使您更改数字的顺序也可以使用

示例:

新数组:[15, 7, 11, 2],目标 = 9,

输出: [1, 3].

我不明白解决方案有什么问题,希望有人能解释一下。谢谢

【问题讨论】:

  • 你正在做的问题是 j 从 0 开始索引。所以它会考虑两次驻留在 i 处的任何元素。 j 应始终为 i+1。作为您给出的示例,假设 i=0 和 j=0,现在它将检查 num[0]+num[0] 即 3+3 并返回 0,0。但问题表明没有数字可以使用两次。所以如果你这样设置 j=i+1 3+2 !=6 会产生下一个元素。

标签: javascript arrays algorithm


【解决方案1】:

我们可以通过使用地图/对象在 O(n) 内解决这个问题。 我们可以维护一个映射或对象,它将使用索引保存所有值,然后我们可以迭代数组并为每个值找到 target-nums[i] 并在映射/对象中找到该值。 让我们通过例子来看看:-

nums=[2,7,11,15]
target = 9;
then map/object will be 
mm={
2 : 0,
7: 1,
11: 2,
15: 3
}


then for each value, we will find diff and find that diff in map/object.
for i=0 diff= 9-2=7 and mm.has(7) is true so our answer is 2 and 7. 
for their index we can use mm.get(7) and i. 
return [mm.get(7), i]

var twoSum = function(nums, target) {
    let mm=new Map();
    for(let i=0;i<nums.length;i++){
        mm.set(nums[i],i);
    }
    let diff=0;
    let j;
    for(let i=0;i<nums.length;i++){
        diff=target-nums[i];
        if(mm.has(diff) && i!=mm.get(diff)){
           j=mm.get(diff);
            if(j>i){
                return [i,j];
            }else{
               return [j,i];
            }
        }
    }
};

运行时间:76 毫秒,比 88.18% 的 JavaScript 在线提交的 Two Sum 快。 内存使用:41.4 MB,不到 JavaScript 在线提交的 2 Sum 的 13.32%。

【讨论】:

  • 它是否适用于 [2,15,11,2] 目标为 4,我相信 JS 中的对象只能包含唯一键。 mm={ 2 : 0, //2:3 将在这里覆盖 7: 1, 11: 2,} 但无论如何,第一个元素本身不会被比较,即在这种情况下为 2。
  • 在这个问题中,我们认为所有元素都是独一无二的。如果要使用重复项,则可以添加索引数组。 2 : [0 ,3] 7 : 1 11 : 2 并且在检查时您可以检查所有可能的情况或我们可以用其他方法解决的问题。
【解决方案2】:

我想这可能是一个更好的解决方案。这提供了一个线性解决方案,而不是嵌套循环。

(PS:indexOf 也有点像 O(n) 复杂度的循环)

var twoSum = function (nums, target) {
    const hm = {}
    nums.forEach((num, i) => {
      hm[target - num] = i
    })

    for (let i = 0; i < nums.length; i++) {
      if(hm[nums[i]] !== undefined && hm[nums[i]] !== i) {
        return ([hm[nums[i]], i])
      }
    }
};

【讨论】:

    【解决方案3】:
    var twoSum = function(nums, target) {
        var numlen = nums.length;
        for(let i=0; i<=numlen; i++){
            for(let j=i+1;j<numlen;j++){
                var num1 = parseInt(nums[i]);
                var num2 = parseInt(nums[j]);
                var num3 = num1 + num2;
                if(num3 == target){
                return[i,j]
                }
            }
        }
        
        
    };
    

    【讨论】:

    • 正如目前所写,您的答案尚不清楚。请edit 添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。你可以找到更多关于如何写好答案的信息in the help center
    【解决方案4】:

    另一种以 O(n) 时间复杂度解决此问题的有效解决方法是不使用嵌套循环。我注释了这些步骤,以便 JS 开发人员易于理解。这是我使用 golang 的解决方案:

    func twoSum(intArray []int, target int) []int {
        response := []int{-1, -1}  // create an array as default response
    
        if len(intArray) == 0 {  // return default response if the input array is empty
            return response
        }
    
        listMap := map[int]int{} // create a Map, JS => listMap = new Map()
    
        for index, value := range intArray { // for loop to fill the map
            listMap[value] = index
        }
    
        for i, value := range intArray { // for loop to verify if the subtraction is in the map
            result := target - value
            if j, ok := listMap[result]; ok && i != j { // this verify if a property exists on a map in golang. In the same line we verify it i == j.
                response[0] = i
                response[1] = j
                return response
            }
        }
    
        return response
    }
    

    【讨论】:

      【解决方案5】:
      var twoSum = function(nums, target) {
          for(var i=0;i<nums.length;i++){
              for(var j=i+1;j<nums.length;j++){
              temp = nums[i]+nums[j];
              if(temp == target){
                  return [i,j]
              }
            }
          }
          
      };
      
      
      console.log(twoSum([15, 7, 11, 2],9))
      console.log(twoSum([3, 2, 4],6))
      console.log(twoSum([3,3],6))
      

      完美运行,运行时间:72 毫秒小于 84 毫秒

      【讨论】:

        【解决方案6】:

        您可以使用一种非常简单的技术。
        基本上,您可以检查目标和当前迭代中的元素的差异是否存在于数组中。

        假设同一个索引不能被使用两次

        nums = [3, 2, 4], target = 6
        nums[0] = 3
        target = 6
        diff = 6 - 3 = 3
        nums.indexOf[3] = 0 // FAILURE case because it's the same index
        
        // move to next iteration
        nums[1] = 2
        target = 6
        diff = 6 - 2 = 4
        nums.indexOf(4) = 2 // SUCCESS '4' exists in the array nums
        // break the loop
        

        这是leetcode 接受的答案。

        /**
         * @param {number[]} nums
         * @param {number} target
         * @return {number[]}
         */
        var twoSum = function(nums, target) {
            for (let index = 0; index < nums.length; index++) {
                const diff = target - nums[index];
                const diffIndex = nums.indexOf(diff);
                // "diffIndex !== index" takes care of same index not being reused
                if (diffIndex !== -1 && diffIndex !== index) {
                    return [index, diffIndex];
                }
            }
        };
        

        运行时间:72 毫秒,比 93.74% 的 JavaScript 在线提交要快。
        内存使用量:38.5 MB,不到 90.55% 的 JavaScript 在线提交两个总和。

        任何人都可以帮助我减少内存使用吗?

        【讨论】:

          【解决方案7】:
          var twoSum = function(nums, target) {
              
             for(let i=0; i<nums.length; i++){
                 for(let j=i+1; j<nums.length; j++){
                     if(nums[j] === target - nums[i]){
                        return [i, j];
                     }
                 }
             }
          };
          

          【讨论】:

          • 请不要只发布代码作为答案,还要解释您的代码的作用以及它如何解决问题的问题。带有解释的答案通常更有帮助,质量更高,更有可能吸引投票。
          【解决方案8】:
          var twoSum = function (nums, target) {
          var len = nums.length;
          for (var i = 0; i < len; i++) {
              for (var j = i + 1; j < len; j++) {
                  if (nums[i] + nums[j] == target) {
                      return [i,j];
                  }
              }
            }
          };
          

          【讨论】:

          • 我在这里看到了你的愿景,这会快一点@Mridul
          【解决方案9】:

          我不明白解决方案有什么问题,我希望 谁能解释一下?

          这里你的内部和外部循环都从0th 开始,所以在[3,2,4] and target 6 的情况下,它将返回[0,0],因为3 + 3 等于目标,所以采取关心相同的索引元素没有被使用两次在外循环和内循环之间产生了1 的差异


          使外循环从0th 索引和值为i+1的内循环开始

          var twoSum = function(nums, target) {
              for(let i = 0; i < nums.length; i++){
                  for(let j = i+1; j < nums.length; j++){
                      if(nums[i] + nums[j] == target){
                          return [i, j]
                      }
                  }
              }
          };
          
          console.log(twoSum([15, 7, 11, 2],9))
          console.log(twoSum([3, 2, 4],6))

          【讨论】:

          • 找不到两个号码怎么回?
          • @CodeManiac 啊,所以它会返回undefined。我以为你必须返回一个空数组。
          • @0x499602D2 只是想避免疯狂的猜测,因为没有关于此问题的信息,所以将其保留为操作的原始代码,但如果我必须这样做,我将始终保持相同类型的返回值,以便它更容易直接使用函数的返回值,而不是检查返回值的类型,然后使用进一步的操作
          【解决方案10】:

          您的解决方案按预期工作。对于nums = [3, 2 ,4]target = 6[0, 0]nums[0] + nums[0] = 3 + 3 = 6 所列问题的有效解决方案。

          如果您需要两个不同的索引(据我了解,这不是任务所必需的),您可以添加额外的不等式检查 (nums[i] + nums[j] == target &amp;&amp; i != j)。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2019-03-30
            • 2018-03-09
            • 1970-01-01
            • 1970-01-01
            • 2014-02-18
            • 2014-02-09
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多