【问题标题】:Finding out the minimum difference between elements in an array找出数组中元素之间的最小差异
【发布时间】:2012-09-02 02:12:39
【问题描述】:

我有一个包含有限个值的整数数组。我的工作是找出数组中任意两个元素之间的最小差异。

考虑数组包含

4, 9, 1, 32, 13

这里的差是 4 和 1 之间的最小值,所以答案是 3。

解决这个问题的算法应该是什么。另外,我不知道为什么,但我觉得使用树,这个问题可以相对容易地解决。可以吗?

【问题讨论】:

标签: algorithm


【解决方案1】:

最小差异将是排序顺序中连续对之间的差异之一。对数组进行排序,并通过相邻的数字对寻找最小的差异:

int[] a = new int[] {4, 9, 1, 32, 13};
Arrays.sort(a);
int minDiff = a[1]-a[0];
for (int i = 2 ; i != a.length ; i++) {
    minDiff = Math.min(minDiff, a[i]-a[i-1]);
}
System.out.println(minDiff);

This prints 3.

【讨论】:

  • 好的.. 我明白你在说什么。但是排序本身需要 O(n.log n) 时间。我只是好奇,但我们可以不排序吗!
  • @CSSS 如果您进行基数排序,则为 O(n)
  • @CSSS 我认为你不能比O(N*LogN) 更快地做到这一点。您必须至少遍历数组的元素一次,并且对于每个元素,您需要找到它的最佳“对应物”进行减法。如果你使用一棵树,你能做的最好的就是Log(N)
  • @CSSS 遍历数组,并从其元素构建二叉搜索树。每次向 BST 添加节点时,请检查新添加的元素与您在查找树中新元素的位置时走过的每个节点之间的差异。差异最小的对应节点将在这些节点之一中。在树中插入一个节点需要Log(N),总共需要O(N*Log(N)).
  • 是的,构建二叉搜索树只是现实中的另一种排序方式。
【解决方案2】:

您可以利用您正在考虑整数的事实 制作线性算法:

  1. 第一遍: 计算最大值和最小值
  2. 第二遍: 分配一个长度为 (max - min + 1) 的布尔数组,假初始化, 并将数组中每个值的第 (value - min)th 值更改为 true
  3. 第三遍: 计算布尔数组的真值条目的索引之间的差异。

【讨论】:

  • 这在N 中是线性的,但对max-min 也有线性依赖关系,这可能会非常糟糕。
【解决方案3】:

虽然所有答案都是正确的,但我想展示负责n log n 运行时间的底层算法。 分而治之的方法是找到两点之间的最小距离或找到一维平面中最近的点。

一般算法:

  • 设 m = 中位数 (S)。
  • 在 m 处将 S 分为 S1、S2。
  • δ1 = 最近对 (S1)。
  • δ2 = 最近对 (S2)。
  • δ12 是穿过切口的最小距离。
  • 返回 δ = min(δ1, δ2, δ12)。

这是我用 Javascript 创建的示例:

// Points in 1-D
var points = [4, 9, 1, 32, 13];

var smallestDiff;

function mergeSort(arr) {
  if (arr.length == 1)
    return arr;

  if (arr.length > 1) {
    let breakpoint = Math.ceil((arr.length / 2));
    // Left list starts with 0, breakpoint-1
    let leftList = arr.slice(0, breakpoint);
    // Right list starts with breakpoint, length-1
    let rightList = arr.slice(breakpoint, arr.length);

    // Make a recursive call
    leftList = mergeSort(leftList);
    rightList = mergeSort(rightList);

    var a = merge(leftList, rightList);
    return a;
  }
}

function merge(leftList, rightList) {
  let result = [];
  while (leftList.length && rightList.length) {
    // Sorting the x coordinates
    if (leftList[0] <= rightList[0]) {
      result.push(leftList.shift());
    } else {
      result.push(rightList.shift());
    }
  }

  while (leftList.length)
    result.push(leftList.shift());

  while (rightList.length)
    result.push(rightList.shift());

  let diff;
  if (result.length > 1) {
    diff = result[1] - result[0];
  } else {
    diff = result[0];
  }

  if (smallestDiff) {
    if (diff < smallestDiff)
      smallestDiff = diff;
  } else {
    smallestDiff = diff;
  }
  return result;
}

mergeSort(points);

console.log(`Smallest difference: ${smallestDiff}`);

【讨论】:

    【解决方案4】:

    我会将它们放在O(nlogn) 中的一个堆中,然后一个接一个地弹出并获得我弹出的每个元素之间的最小差异。最后我会有最小的差异。但是,可能有更好的解决方案。

    【讨论】:

      【解决方案5】:

      这实际上是对one-dimension 中的closest-pair 问题的重述。 https://en.wikipedia.org/wiki/Closest_pair_of_points_problem http://www.cs.umd.edu/~samir/grant/cp.pdf

      正如下面引用的 Wikipedia 文章所指出的,该问题的最佳决策树模型也在 Ω(nlogn) 时间运行。

      【讨论】:

        【解决方案6】:

        分享最简单的解决方案。

        function FindMin(arr) {
        
            //sort the array in increasing order
        
            arr.sort((a,b) => {
               return a-b;
            });
        
            let min = arr[1]-arr[0];
        
            let n = arr.length;
        
            for (var i=0;i<n;i++) {
        
              let m = arr[i+1] - arr[i];
              if(m < min){
                m = min;
              }
            }
        
            return m; // minimum difference.
          }
        

        【讨论】:

          【解决方案7】:

          给定的问题可以在 O(n) 时间内轻松解决。看下面我写的代码。

              import java.util.Scanner;
              public class Solution {
              public static void main(String [] args) {
                  Scanner input = new Scanner(System.in);
                  int i, minDistance = 999999;
                  boolean flag = false;
                  int capacity = input.nextInt();
                  int arr[] = new int[capacity];
                  for (i = 0; i < capacity; i++) {
                      arr[i] = input.nextInt();
                  }
          
                  int firstElement = input.nextInt();
                  int secondElement = input.nextInt();
          
                  int prev = 0;
          
                  for (i = 0; i < capacity; i++) {
                      if (arr[i] == firstElement || arr[i] == secondElement) {
                          prev = i;
                          break;
                      }
                  }
          
                  for (; i < capacity; i++) {
                      if(arr[i] == firstElement || arr[i] == secondElement) {
                          if(arr[i] != arr[prev] && minDistance > Math.abs(i - prev)) {
                              minDistance = Math.abs(i - prev);
                              flag = true;
                              prev = i;
                          } else {
                              prev = i;
                          }
                      }
                  }
          
                  if(flag)
                      System.out.println(minDistance);
                  else
                      System.out.println("-1");
              }
          }
          

          【讨论】:

          • 如果您解释了算法背后的逻辑,而不是提供没有任何解释的代码,您的答案会好得多。
          【解决方案8】:

          在 Python 3 中,这个问题可以通过使用模块 itertools 来简化,该模块提供了可用于列表的组合。从该列表中,我们可以找到每个组合的总和并找到这些值的最小值。

          import itertools
          
          arr = [4, 9, 1, 32, 13]
          
          if len(arr) > 1:
              min_diff = abs(arr[0] - arr[1])
          else:
              min_diff = 0
          
          for n1, n2 in itertools.combinations(arr, 2): # Get the combinations of numbers
              diff = abs(n1-n2) # Find the absolute difference of each combination
              if min_diff > diff:
                  min_diff = diff # Replace incase a least differnce found
          
          print(min_diff)  
          

          【讨论】:

          • 虽然这可能会回答问题,但稍微解释一下可以提高答案的长期价值。
          • @jrook 更新了答案给出解释。
          • cmets 混合了absolute differenceminimum of sum。一个包含大约len(arr)² 元素的列表是以“非pythonic”方式构建的。
          • @greybeard 编辑了答案以避免使用列表。这个呢?
          • 复杂度是多少?如果您检查所有组合,那么它是 O(n^2),因此比其他答案慢得多