【问题标题】:Two Sum on LeetCodeLeetCode 上的两个 Sum
【发布时间】:2015-05-04 00:40:53
【问题描述】:

我正在尝试做一个 LeetCode 问题:

给定一个整数数组,找出两个数之和 一个特定的目标编号。

函数 twoSum 应该返回两个数字的索引,使得 它们加起来就是目标,其中 index1 必须小于 index2。 请注意,您返回的答案(index1 和 index2)是 不是从零开始的。

您可以假设每个输入都只有一个解决方案。

输入:numbers={2, 7, 11, 15}, target=9 输出:index1=1, index2=2

第一次尝试是使用两个 for 循环,这给了我 O(n^2),不幸的是它没有通过。因此我尝试使用:

target - current = index

并搜索该索引是否存在于字典中。

这是我的代码:

class Solution:
    def twoSum(self, nums, target):
        dic = {}

        #A number can appear twice inside the same index, so I use a list
        for i in xrange(0, len(nums)):
            try:
                dic[nums[i]].append(i)
            except:
                dic[nums[i]] = []
                dic[nums[i]].append(i)

        try:
            for items_1 in dic[nums[i]]:
                for items_2 in dic[target-nums[i]]:
                    if(items_1+1 != items_2+1):
                        l = []
                        if(items_2+1 > items_1+1):
                            l.append(items_1+1)
                            l.append(items_2+1)
                        else:
                            l.append(items_2+1)
                            l.append(items_1+1)
                        return l
        except:
            pass

我在本地开发了这个,我能够通过 LeetCode 抱怨的测试用例之一得到正确的结果:[-3,4,3,90], 0

我得到的输出是 [1, 3],但是在 LeetCode 上它返回 null,有人知道为什么会这样吗?

【问题讨论】:

  • 一个数字在 nums 列表中出现两次真的很重要吗?重要的是你得到 a 索引,对吗?
  • 嗯...如果数字是 [0, 3, 4, 0],那么正确的值应该是第 1 和第 4 个索引。但是,由于 0 索引已经在第 1 个索引处,所以会发生第 4 个索引不在字典中。
  • 你想让我告诉你我会怎么写吗?
  • 你为什么要上课?该类只包含一个方法。为什么不删除类定义行并将方法保留为独立函数?
  • 类需要提交答案,在我本地开发中,我没有包含类。

标签: python


【解决方案1】:
def twosum(nums=(6, 7, 11, 15, 3, 6, 5, 3), target=6):
    lookup = dict(((v, i) for i, v in enumerate(nums)))
    return next(( (i+1, lookup.get(target-v)+1) 
            for i, v in enumerate(nums) 
                if lookup.get(target-v, i) != i), None)

我没有对此进行过广泛的测试,但基本逻辑应该是合理的。该算法可以分为两个阶段:

  1. 为所有索引创建一个 value->index 字典,以 nums 为单位的值对。请注意,您可以有多个具有不同索引的值。在这种情况下,最高的索引将存储在字典中,而较低的索引将被覆盖。当然,可以修改此行为,但我认为不需要针对此问题,因为问题陈述的一部分是这样的:“您可以假设每个输入都只有一个解决方案。”因此,每个输入都有一个唯一的输出,因此我们永远不必担心返回“错误的一对”索引。

  2. 遍历nums的枚举,得到i作为索引,v作为值。检查target-v 是否是我们创建的字典中的键,同时断言该键指向的值是not i。如果这是真的,请返回元组 i+1, lookup.get(target-v)+1

【讨论】:

  • 给出与我的代码相同的确切答案,但为什么我的代码不被接受? :(
  • @user1157751 不幸的是,您的代码与我的代码具有相同的底层逻辑吗?细微差别很重要,例如处理项目的顺序等。
  • @user1157751 顺便说一句,我注意到你的逻辑是target - current = index,它真的应该是target - current = value that has different index than current。也许,这会导致问题。
  • 这个例子是错误的。当您运行代码并从 twosum 打印返回值时,您会得到 (4,8) 但正确答案是 (4,7)。
  • @PaulCornelius 请注意:“您可以假设每个输入都只有一个解决方案。”我明确指出字典将值更新为最高索引。这就是我的解决方案给出 (4, 8) 的原因。这个例子只是为了展示第一行的行为。即使该句子不在问题陈述中,我的答案仍然是正确的,因为 (4, 8) 是一对有效的索引,指向的值总和为目标。跨度>
【解决方案2】:

你想要一些类似的东西:

#! python3

def two_sum(arr,targ):
    look_for = {}
    for n,x in enumerate(arr,1):
        try:
            return look_for[x], n
        except KeyError:
            look_for.setdefault(targ - x,n)

a = (2,7,1,15)
t = 9
print(two_sum(a,t))  # (1,2)

a = (-3,4,3,90)
t = 0
print(two_sum(a,t))  # (1,3)

在这里,您可以根据需要构建值字典。该字典由您正在寻找的值作为键,并且对于每个值,您跟踪其首次出现的索引。一旦你得到一个满足问题的值,你就完成了。只有一个 for 循环。

唯一的其他细节是为每个索引添加 1 以满足索引从 1 开始的荒谬要求。就像那会教你 Python 编程一样。

使用 setdefault 函数将键添加到字典中,因为如果键已经存在,您希望保留其值(最低索引)。

【讨论】:

    【解决方案3】:

    我刚刚通过了以下代码。利用字典和注释,即只有一个解决方案。在查找字典中保存num时,在保存的查找字典中搜索target-num。当nums中有两个相同的值时,这种方法可以节省空间,也可以防止索引覆盖。

    def twosum(self, nums, target):
        lookup = {}
        for cnt, num in enumerate(nums):
            if target - num in lookup:
                return lookup[target-num], cnt
            lookup[num] = cnt            
    

    【讨论】:

      【解决方案4】:

      此答案使用从零开始的索引,因为这是索引的正常方式,而不是从一开始的索引。它还使用描述性变量名称,并且是为了理解而编写的。

      from typing import List, Tuple
      
      def twosum_indices_linear(nums: List[int], target: int) -> Tuple[int, int]:
          numtoindexmap = {}
          for num1_index, num1 in enumerate(nums):
              num2 = target - num1
              try:
                  num2_index = numtoindexmap[num2]
              except KeyError:
                  numtoindexmap[num1] = num1_index  
                  # Note: Use `numtoindexmap.setdefault(num1, num1_index)` instead for lowest num1_index.
              else:
                  return tuple(sorted([num1_index, num2_index]))
      

      例子:

      print(twosum_indices_linear([2, 7, 11, 15], 9))
      (0, 1)
      
      print(twosum_indices_linear([3, 3], 6))
      (0, 1)
      
      print(twosum_indices_linear([6, 7, 11, 15, 3, 6, 5, 3], 6))
      (4, 7)
      

      信用:answer by joeg

      【讨论】:

        【解决方案5】:
        public static int[] twoSum1(int[] nums, int target) 
        {
            int[] result = new int[2];
            Map<Integer, Integer> map = new HashMap<>();
        
         
            for(int i=0; i<nums.length; i++)
                map.put(nums[i],i);
            
            
            for(int i=0; i<nums.length; i++)
            {
                int index = i;
                int anotherValue = target-nums[index];
                
                if(map.get(anotherValue)!=null && map.get(anotherValue)!=i)
                {
                    result[0] = index;
                    result[1] = map.get(target-nums[index]);
                    
                    System.err.println("result[0]: " + result[0]);
                    System.err.println("result[1]: " + result[1]);
                    
                    return result;
                }
            }        
            return result;
        }
        

        【讨论】:

          【解决方案6】:
          def twoSum(nums,target):
              k={value:index for index, value in enumerate(nums)} 
              # using dictionary comprehesion to create a dictionary that maps value to index 
              ans=[[j,k[target-x]] for j,x in enumerate(nums) if target-x in k] 
              # use list comprehension to create a set of answers; make sure no key error by using 'if target-x in k'
              ans=[x for x in ans if x[0] != x[1]] 
              # make sure the two indexes are not the same. E.g. twoSum([1,2,0],2) returns [[0,0],[0,1],[1,2],[2,1]]; and [0,0] is a wrong answer  
              return ans[0]
          

          这个解决方案非常省时(比 leetcode 上 80% 的解决方案要快),但占用大量内存。

          【讨论】:

            【解决方案7】:

            我喜欢

                def two_sum(arr,targ):
                    look_for = {}
                    for n,x in enumerate(arr,1):
                        try:
                           return look_for[x], n
                        except KeyError:
                           look_for.setdefault(targ - x,n)
            

            上面,但由于调用枚举对于大型数组花费太长时间而导致 timedome 失败。最好跳过枚举并只保留索引计数:

            def findCombo(l,target):
                lookup = {}
                n = 0
                for x in l:
                    try:
                        return (n,lookup[x])
                    except KeyError:            
                        lookup.setdefault (target-x,n)
                    n = n + 1
            
                return None
            

            注意:Python 计时问题使用从 0 开始的索引

            【讨论】:

              【解决方案8】:

              一次性哈希表

              这可以一次性完成。 Teo 怎么样? 好吧,当它迭代和插入元素到散列中时,它还应该回头检查当前元素的补码是否已经存在于散列中。如果存在,我们已经找到解决方案并立即返回。

              复杂性:

              时间复杂度:O(n)。我们只遍历包含 n 个元素的列表一次。每次在表格中查找只需 O(1) 时间。

              空间复杂度:O(n)。所需的额外空间取决于哈希表中存储的项目数,该哈希表最多存储 n 个元素。

              const nums = [2, 7, 11, 15];
              const target = 9;
              
              
              /**
               * @param {number[]} nums
               * @param {number} target
               * @return {number[]}
               */
              let twoSum = function(nums, target) {
                  let map = new Map;
                  for (var i = 0; i < nums.length; i++) {
                      let complement = target - nums[i];
                      if (map.has(complement)) {
                          return [map.get(complement), i]
                      }
                      map.set(nums[i], i);
                  }
                  throw new Error('No two sum solution'); 
              }
              
              console.log(twoSum(nums, target));

              【讨论】:

                【解决方案9】:

                这是我的答案

                class Solution:
                    def twoSum(self, nums, target):
                        ls = []
                        for i in range(0, len(nums)):
                            item = target - nums[i]
                            nums[i] = "done"
                            if item in nums:
                                if i != nums.index(item):
                                    ls.append(i)
                                    ls.append(nums.index(item))
                                    return ls
                

                【讨论】:

                • 如果数组为 [3,2,4] 且目标 =6,则失败。它返回 [0,0] 但预期为 [1,2]
                【解决方案10】:

                如果有人还在为这个问题寻找 javascript 解决方案,

                /** 
                1. Two Sum
                
                Given an array of integers, return indices of the two numbers such that they add up to a specific target.
                
                You may assume that each input would have exactly one solution, and you may not use the same element twice.
                
                Example:
                
                Given nums = [2, 7, 11, 15], target = 9,
                
                Because nums[0] + nums[1] = 2 + 7 = 9,
                
                return [0, 1].
                * */
                
                /**
                 * @param {number[]} nums
                 * @param {number} target
                 * @return {number[]}
                 */
                function twoSum(nums, target) {
                  const numsObjs = {}; // create nums obj with value as key and index as value eg: [2,7,11,15] => {2: 0, 7: 1, 11: 2, 15: 3}
                
                  for (let i = 0; i < nums.length; i++) {
                    const currentValue = nums[i];
                
                    if (target - currentValue in numsObjs) {
                      return [i, numsObjs[target - currentValue]];
                    }
                    numsObjs[nums[i]] = i;
                  }
                
                  return [-1, -1];
                }
                
                console.log(twoSum([3,7,3], 6))

                【讨论】:

                • 但这两次使用相同的元素。您有多个对 nums 的引用
                【解决方案11】:

                我的单行解决方案:

                class Solution:
                    def twoSum(self, nums: List[int], target: int) -> List[int]:
                        res=[[nums.index(val),nums[ind +1:].index(target-val)+ ind +1] for ind,val in enumerate(nums) if target -val in nums[ind +1:]]
                        return res[0]
                

                如果有人感兴趣,我可以解释:)

                【讨论】:

                • 无论如何你都应该添加你的解释(不要等待被问到)。这将使您的答案变得更好,并且更有可能吸引投票。
                【解决方案12】:

                我认为上面的解决方案看起来很复杂。

                def twoSum(nums: List[int], target: int) -> List[int]:
                   output = []
                   for i in nums:
                        for j in nums:
                            if i + j == target and nums.index(i) != nums.index(j):
                                output.append(nums.index(i))
                                output.append(nums.index(j))
                                return output
                
                print(twoSum([2,7,11,15],9))
                print(twoSum([3,2,4],6))
                

                #输出

                [0, 1]
                [1, 2]
                

                【讨论】:

                  【解决方案13】:

                  @Shashank 的答案是正确的,但是这个答案的结果从数组中的索引 1 开始,所以 leetcode 不会接受它。所以这里是相同的解决方案,只是简单地更改了从索引 0 开始的数组。

                  class Solution:
                      def twoSum(self,nums, target):
                          lookup = dict(((v, i) for i, v in enumerate(nums)))
                          return next(( (i, lookup.get(target-v)) 
                              for i, v in enumerate(nums) 
                                  if lookup.get(target-v, i) != i), None)
                  
                  

                  【讨论】:

                    【解决方案14】:

                    这个答案是节省内存的,坐使用列表弹出方法,但需要更长的时间

                    class Solution:   
                        def twoSum(self, nums: List[int], target: int) -> List[int]:
                            
                            while len(nums)>0:
                                ind = len(nums)-1
                                item = nums.pop()
                                if target-item in nums:
                                    return [ind, nums.index(target-item)]
                    

                    【讨论】:

                      【解决方案15】:

                      这是我在 JavaScript

                      中更快的回答
                      const nums = [2,7,11,15];
                      const target = 9;
                      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){
                                  console.log(i, j);
                                }
                            }
                          }
                      };
                      
                      twoSum(nums, target);
                      

                      【讨论】:

                        【解决方案16】:

                        def twoSum(self, nums: List[int], target: int) -> List[int]:

                            d = dict()
                            
                            for i in range(0, len(nums), 1):
                                
                                if (d.get(target-nums[i]) != None):
                                    return [i, d.get(target-nums[i])]
                                
                                d[nums[i]] = i
                                
                          
                            
                        

                        我最初也为多个循环而苦苦挣扎,最后瘦到了这个。

                        【讨论】:

                          【解决方案17】:
                          class Solution:
                              def twoSum(self, nums: List[int], target: int) -> List[int]:
                                  r = []
                          
                                  for i in range(len(nums)):
                                      temp = target - nums[i]
                                      if temp in r:
                                          return [i,nums.index(temp)]
                          
                                      r.append(nums[i])
                          

                          【讨论】:

                          • 为什么要使用它?请在您的答案中添加一些解释,以便其他人可以从中学习
                          • 假设列表有 [4,5,6,7] 并且目标是 11,循环将检查所有值。就像在这个例子中一样,它以 4 开头,所以 11-4 = 7 出现在列表中。所以输出将是 4 和 7 的索引,即 [0,3]
                          • 请将所有此类解释添加到答案中,而不是添加到评论部分
                          • 对不起,尼科,我是新手。下次我将在答案中添加解释。 :-)
                          • 找到为 SO 做出贡献的新人总是好的 - 不要犹豫发布其他问题的答案,当然也可以自己发布问题!
                          【解决方案18】:
                          nums = [2, 7, 11, 15]
                          target = 9
                          l = []
                          x = 1
                          length = len(nums) - 1
                          for i in nums:
                              l.append(nums.index(i))
                              if (target - i) in nums[x:]:
                                 l.append(length - nums[::-1].index(target - i))
                                 break
                              else:
                                 l = []
                                 x = x + 1
                          print(l)
                          

                          请在此处查看提交:https://www.youtube.com/watch?v=PeJtMogExbo

                          【讨论】:

                          • 虽然这段代码 sn-p 可以解决问题,including an explanation 确实有助于提高您的帖子质量。请记住,您是在为将来的读者回答问题,而这些人可能不知道您提出代码建议的原因。
                          【解决方案19】:

                          这是我在 C++ 中的答案。我希望你能把它转换成 python

                          class Solution {
                          public:
                              vector<int> twoSum(vector<int>& nums, int target) {
                                  unordered_set<int>s;
                                  vector<int>ans;
                              int j =0;
                              for(int i=0;i<nums.size();i++)
                              {
                                  int temp = target -nums[i];
                                  //int tempInd = i ;
                                  if(s.find(temp)!=s.end()){
                                      //cout<<i<<" ";
                                       ans.push_back(i) ;
                                      for(int j=0;j<nums.size();j++)
                                      {
                                          if(temp == nums[j]){
                                              //cout<<j<<endl;
                                              ans.push_back(j) ;
                                          break;
                                          }
                                      }
                                  }
                                  s.insert(nums[i]);
                          
                              }
                                  return ans ;
                              }
                          };
                          

                          【讨论】:

                            猜你喜欢
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 2022-11-11
                            • 1970-01-01
                            • 1970-01-01
                            • 2022-11-13
                            相关资源
                            最近更新 更多