【问题标题】:How to write an algorithm to check if the sum of any two numbers in an array/list matches a given number?如何编写算法来检查数组/列表中任意两个数字的总和是否与给定数字匹配?
【发布时间】:2010-04-19 10:38:02
【问题描述】:

如何编写算法来检查数组/列表中任意两个数字的总和是否与给定数字匹配 复杂度为nlogn?

【问题讨论】:

  • 你期望输出什么?号码?他们的指数?如果可能有多个结果怎么办?
  • 你想要一个真/假答案“是的,有一对”还是你想要所有对?或者所有可能的组合都可以提供所需的总和?

标签: algorithm language-agnostic


【解决方案1】:

我确信有更好的方法,但这里有一个想法:

  1. 排序数组
  2. 对于数组中的每个元素 e,二进制搜索补码 (sum - e)

这两个操作都是O(n log n)

【讨论】:

  • 另外,排序后,丢弃所有大于和的数字。我假设你有所有的正整数。
  • 是的,我就是这么想的,然后我忙着计算复杂性,我从来没有想过这两个操作都是 o(nlogn)
  • 您实际上不必搜索每个元素。由于您已经对数组进行了排序,因此请停止在 sum/2 处搜索(不会影响大 O,但仍然:p)
【解决方案2】:

这可以在O(n) 中使用哈希表来完成。用数组中的所有数字初始化表,以数字为键,频率为值。遍历数组中的每个数字,查看表中是否存在(sum - number)。如果是这样,你就有了比赛。遍历数组中的所有数字后,您应该有一个总和为所需数字的所有对的列表。

array = initial array
table = hash(array)
S = sum

for each n in array
    if table[S-n] exists
        print "found numbers" n, S-n

n 和 table[S-n] 两次引用同一个数的情况可以额外检查处理,但复杂度依然O(n)

【讨论】:

  • 这应该是被接受的答案,因为它是 O(n) 而接受的答案是 O(n logn)
  • 除非作者能够解释他提出的解决方案如何处理非独特的输入集,否则不应将其视为最佳答案。 (如果最初随机组中的某些数字相互重复怎么办)?
  • 哈希表中的值将代表一个数字在列表中出现的次数。这将允许处理重复项。
【解决方案3】:

使用hash table。将每个数字及其索引插入哈希表。然后,让S 成为您想要的总和。对于初始数组中的每个数字array[i],查看您的哈希表中是否存在S - array[i],其索引不同于i

平均情况是O(n),最坏情况是O(n^2),所以如果您害怕最坏情况,请使用二分搜索解决方案。

【讨论】:

  • 我没有得到最坏的情况。使用哈希表应该让您O(1) 进行插入和查找(小心),或者您是否考虑了潜在的哈希冲突?无论如何,这似乎比使用二分搜索更好。
  • 是的,可能存在哈希冲突。例如,考虑包含 n 的数组 {1, 1, 1, ..., 1, 1, 1, ...}。我们希望总和为 20。您将在哈希表中的相同位置添加所有的。然后,对于每个 1,您将检查 19 是否在数组中。假设值 19 映射到哈希表中与值 1 相同的位置。这意味着对于每个n,您将在哈希表中进行n 检查,从而为您提供二次时间复杂度。对于有解决方案的情况(使用 3 个值 - 一个占优),可以找到类似的示例
  • 您可以将频率映射为每个关联数字的值。因此,如果您有 8 个 1,则哈希将映射 1 => 8。例如,当需要 2 的总和时,您可以进行额外检查 - 如果当前数字等于目标数字 (S - array[i]),那么它的频率必须至少为 2。
【解决方案4】:

假设我们想在数组 A 中找到两个数字相加等于 N。

  1. 对数组进行排序。
  2. 在数组中找到小于 N/2 的最大数。将该数字的索引设置为 lower
  3. upper 初始化为 lower + 1。
  4. 设置 sum = A[lower] + A[upper]。
  5. 如果 sum == N,则完成。
  6. 如果sum upper。
  7. 如果sum > N,则减
  8. 如果 lowerupper 在数组之外,则没有任何匹配项。
  9. 回到 4。

排序可以在 O(n log n) 内完成。搜索是在线性时间内完成的。

【讨论】:

    【解决方案5】:

    这是在 Java 中:这甚至可以删除可能的重复项。运行时 - O(n^2)

    private static int[] intArray = {15,5,10,20,25,30};
    private static int sum = 35;
    
    private static void algorithm()
    {
        Map<Integer, Integer> intMap = new Hashtable<Integer, Integer>();
        for (int i=0; i<intArray.length; i++) 
        {
            intMap.put(i, intArray[i]);
            if(intMap.containsValue(sum - intArray[i]))
                System.out.println("Found numbers : "+intArray[i] +" and "+(sum - intArray[i]));
    
        }
        System.out.println(intMap);
    }
    

    【讨论】:

    • 这个解决方案是次优的,因为containsValue在线性时间内运行,因此总运行时间是O(n^2)
    【解决方案6】:
    def sum_in(numbers, sum_):
        """whether any two numbers from `numbers` form `sum_`."""
        a = set(numbers) # O(n)
        return any((sum_ - n) in a for n in a) # O(n)
    

    例子:

    >>> sum_in([200, -10, -100], 100)
    True
    

    【讨论】:

    • 注意:此解决方案允许重复,即不区分 [1][1, 1] 情况。
    【解决方案7】:

    这是 C 中的一个尝试。这不是标记作业。

    // Assumes a sorted integer array with no duplicates
    void printMatching(int array[], int size, int sum)
    {
       int i = 0, k = size - 1;
       int curSum;
       while(i < k)
       {
          curSum = array[i] + array[k];
          if(curSum == sum)
          {
             printf("Found match at indices %d, %d\n", i, k);
             i++;k--;
          }
          else if(curSum < sum)
          {
             i++;
          }
          else
          {
             k--;
          }
       }
    }
    

    这是使用int a[] = { 3, 5, 6, 7, 8, 9, 13, 15, 17 };的一些测试输出

    Searching for 12..
    Found match at indices 0, 5
    Found match at indices 1, 3
    Searching for 22...
    Found match at indices 1, 8
    Found match at indices 3, 7
    Found match at indices 5, 6
    Searching for 4..
    Searching for 50..
    

    搜索是线性的,所以 O(n)。如果您使用其中一种好的排序,那么在幕后发生的排序将是 O(n*logn)。

    由于 Big-O 背后的数学原理,加法项中的较小项将有效地退出您的计算,最终得到 O(n logn)。

    【讨论】:

      【解决方案8】:

      这个是O(n)

      public static bool doesTargetExistsInList(int Target, int[] inputArray)
      {
          if (inputArray != null && inputArray.Length > 0 )
          {
              Hashtable inputHashTable = new Hashtable();
      
              // This hash table will have all the items in the input array and how many times they appeard
              Hashtable duplicateItems = new Hashtable();
      
              foreach (int i in inputArray)
              {
                  if (!inputHashTable.ContainsKey(i))
                  {
                      inputHashTable.Add(i, Target - i);
                      duplicateItems.Add(i, 1);
                  }
                  else
                  {
                      duplicateItems[i] = (int)duplicateItems[i] + 1;    
                  }
      
              }
      
              foreach (DictionaryEntry de in inputHashTable)
              {
                  if ((int)de.Key == (int)de.Value)
                  {
                      if ((int)duplicateItems[de.Key] > 1)
                      return true;
                  }
                  else if (inputHashTable.ContainsKey(de.Value))
                  {
                      return true;
                  }
              }
          }
          return false;
      }
      

      【讨论】:

      • 这使用2遍。但只需 1 次就可以完成,对吧?
      【解决方案9】:

      这是一个算法,如果数组已经排序,则在 O(n) 中运行,如果尚未排序,则在 O(n log n) 中运行。从这里的许多其他答案中获取线索。代码是用 Java 编写的,但这里是一个伪代码,也是从许多现有答案中派生出来的,但通常针对重复项进行了优化

      1. 第一个和最后一个元素是否等于目标的幸运猜测
      2. 使用当前值及其出现次数创建地图
      3. 创建一个包含我们已经看到的项目的访问集,这会优化重复项,例如输入 (1,1,1,1,1,1,2) 和目标 4,我们只计算 0和最后一个元素,而不是数组中的所有 1。
      4. 使用这些变量来计算数组中目标的存在; 将 currentValue 设置为 array[ith]; 将 newTarget 设置为目标 - currentValue; 如果 currentValue 等于 newTarget 则将 expectedCount 设置为 2,否则设置为 1

        AND 仅当 一种。我们之前从未见过这个整数 AND 湾。我们创建的地图中的 newTarget 有一些价值 C。并且 newTarget 的计数等于或大于 expectedCount

      否则 重复第 4 步,直到我们到达数组末尾并返回 false OTHERWISE;

      就像我提到的,访问商店的最佳用途是当我们有重复时,如果没有任何元素是重复的,那将永远不会有帮助。

      https://gist.github.com/eded5dbcee737390acb4 的 Java 代码

      【讨论】:

        【解决方案10】:

        取决于您是否只想要一个总和 O(N) 或 O(N log N) 或所有总和 O(N^2) 或 O(N^2 log N)。在后一种情况下,最好使用 FFT>

        【讨论】:

          【解决方案11】:

          第 1 步:在 O(n logn) 中对数组进行排序

          第 2 步:找到两个索引

          0

          int i=0,j=n;
          while(i<j) {
             int sum = a[i]+a[j];
             if(sum == k)
                  print(i,j)
             else if (sum < k)
                  i++;
             else if (sum > k)
                  j--;
          }
          

          【讨论】:

            【解决方案12】:
                public void sumOfTwoQualToTargetSum()
                {
                    List<int> list= new List<int>();
                    list.Add(1);
                    list.Add(3);
                    list.Add(5);
                    list.Add(7);
                    list.Add(9);
            
                    int targetsum = 12;
            
                    int[] arr = list.ToArray();
            
                    for (int i = 0; i < arr.Length; i++)
                    {
                        for (int j = 0; j < arr.Length; j++)
                        {
                            if ((i != j) && ((arr[i] + arr[j]) == targetsum))
                            {
                                Console.Write("i =" + i);
                                Console.WriteLine("j =" + j);
                            }
                        }
                    }
                }
            

            【讨论】:

              【解决方案13】:
              1. 解决了 Swift 4.0 中的问题
              2. 以 3 种不同方式解决(使用 2 种不同类型的返回 -> 布尔值和索引)

              A) 时间复杂度 => 0(n Log n) 空间复杂度 => 0(n)。

              B) 时间复杂度 => 0(n^2) 空间复杂度 => 0(1)。

              C) 时间复杂度 => 0(n) 空间复杂度 => 0(n)

              1. 根据权衡选择解决方案 A、B 或 C。

                //***********************Solution A*********************//
                //This solution returns TRUE if any such two pairs exist in the array
                func binarySearch(list: [Int], key: Int, start: Int, end: Int) -> Int? { //Helper Function
                
                            if end < start {
                                return -1
                            } else {
                                let midIndex = (start + end) / 2
                
                                if list[midIndex] > key {
                                    return binarySearch(list: list, key: key, start: start, end:  midIndex - 1)
                                } else if list[midIndex] < key {
                                    return binarySearch(list: list, key: key, start: midIndex + 1, end: end)
                                } else {
                                    return midIndex
                                }
                            }
                        }
                
                        func twoPairSum(sum : Int, inputArray: [Int]) -> Bool {
                
                            //Do this only if array isn't Sorted!
                            let sortedArray = inputArray.sorted()
                
                            for (currentIndex, value)  in sortedArray.enumerated() {
                                if let indexReturned =  binarySearch(list: sortedArray, key: sum - value, start: 0, end: sortedArray.count-1) {
                                    if indexReturned != -1 && (indexReturned != currentIndex) {
                                        return true
                                    }
                                }
                            }
                            return false
                        }
                
                 //***********************Solution B*********************//
                 //This solution returns the indexes of the two pair elements if any such two pairs exists in the array
                 func twoPairSum(_ nums: [Int], _ target: Int) -> [Int] {
                
                            for currentIndex in 0..<nums.count {
                                for nextIndex in currentIndex+1..<nums.count {
                                    if calculateSum(firstElement: nums[currentIndex], secondElement: nums[nextIndex], target: target) {
                                        return [currentIndex, nextIndex]
                                    }
                                }
                            }
                
                            return []
                        }
                
                        func calculateSum (firstElement: Int, secondElement: Int, target: Int) -> Bool {//Helper Function
                            return (firstElement + secondElement) == target
                        }
                
                    //*******************Solution C*********************//
                   //This solution returns the indexes of the two pair elements if any such two pairs exists in the array
                   func twoPairSum(_ nums: [Int], _ target: Int) -> [Int] {
                
                            var dict = [Int: Int]()
                
                            for (index, value) in nums.enumerated() {
                                dict[value] = index
                            }
                
                            for (index, value) in nums.enumerated() {
                                let otherIndex = dict[(target - value)]
                                if otherIndex != nil && otherIndex != index {
                                    return [index, otherIndex!]
                                }
                            }
                
                            return []
                        }
                

              【讨论】:

                【解决方案14】:

                这个问题缺少更多细节。就像返回值是什么,对输入的限制。 我已经看到了一些与此相关的问题,可能是这个有额外要求的问题,to return the actual elements that result in the input

                这是我的解决方案版本,应该是O(n)

                import java.util.*;
                
                public class IntegerSum {
                
                    private static final int[] NUMBERS = {1,2,3,4,5,6,7,8,9,10};
                
                    public static void main(String[] args) {
                        int[] result = IntegerSum.isSumExist(7);
                        System.out.println(Arrays.toString(result));
                    }
                
                    /**
                     * n = x + y
                     * 7 = 1 + 6
                     * 7 - 1 =  6
                     * 7 - 6 = 1
                     * The subtraction of one element in the array should result into the value of the other element if it exist;
                     */
                    public static int[] isSumExist(int n) {
                        // validate the input, based on the question
                        // This to return the values that actually result in the sum. which is even more tricky
                        int[] output = new int[2];
                        Map resultsMap = new HashMap<Integer, Integer>();
                        // O(n)
                        for (int number : NUMBERS) {
                            if ( number > n )
                                throw new IllegalStateException("The number is not in the array.");
                            if ( resultsMap.containsKey(number) ) {
                                output[0] = number;
                                output[1] = (Integer) resultsMap.get(number);
                                return output;
                            }
                            resultsMap.put(n - number, number);
                        }
                        throw new IllegalStateException("The number is not in the array.");
                    }
                }
                

                【讨论】:

                  猜你喜欢
                  • 2013-01-01
                  • 2015-10-31
                  • 2018-12-20
                  • 1970-01-01
                  • 2011-12-28
                  • 1970-01-01
                  • 2013-10-29
                  • 1970-01-01
                  • 2016-07-21
                  相关资源
                  最近更新 更多