确定Set S中是否存在两个元素,其和是x正确的解?

hel*_*hod 33 java arrays algorithm

摘自算法简介

描述一个Θ(n lg n)时间算法,给定一组n个整数和另一个整数x,确定S中是否存在两个元素,其和是x.

到目前为止,这是我用Java实现的最佳解决方案:

    public static boolean test(int[] a, int val) {
    mergeSort(a);

    for (int i = 0; i < a.length - 1; ++i) {
        int diff = (val >= a[i]) ? val - a[i] : a[i] - val;

        if (Arrays.binarySearch(a, i, a.length, diff) >= 0) {
            return true;
        }
    }

    return false;
}
Run Code Online (Sandbox Code Playgroud)

现在我的第一个问题是:这是一个正确的解决方案吗?根据我的理解,mergeSort应该在O(n lg n)中执行排序,循环应该取O(n lg n)(n用于迭代乘以O(lg n)进行二进制搜索,得到O(2 l lg) n),所以它应该是正确的.

我的第二个问题是:有更好的解决方案吗?排序阵列必不可少?

cod*_*ict 42

您的解决方案似乎很好 是的,你需要排序,因为它是二进制搜索的先决条件.您可以对逻辑稍作修改,如下所示:

public static boolean test(int[] a, int val) 
{
    Arrays.sort(a);

    int i = 0;            // index of first element.
    int j = a.length - 1; // index of last element. 

    while(i<j)
    {
        // check if the sum of elements at index i and j equals val, if yes we are done.
        if(a[i]+a[j] == val)
            return true;
        // else if sum if more than val, decrease the sum.
        else if(a[i]+a[j] > val)
            j--;
        // else if sum is less than val, increase the sum.
        else
            i++;
    }
    // failed to find any such pair..return false. 
    return false;
}
Run Code Online (Sandbox Code Playgroud)


Syn*_*r0r 14

还有另一个非常快速的解决方案:想象一下,你必须在Java中解决这个大约10亿个整数的问题.你知道,在Java中的整数从去-2**31+1+2**31.

创建一个2**32十亿位的数组(500 MB,在今天的硬件上做的很简单).

迭代你的集合:如果你有一个整数,将相应的位设置为1.

到目前为止O(n).

在您的集合上再次迭代:对于每个值,检查您是否在"当前val - x"处设置了位.

如果你有一个,你就会返回true.

当然,它需要500 MB的内存.

但是,如果您有10亿个整数来解决这个问题,那么这应该围绕任何其他O(n log n)解决方案运行.

上).

  • 我引用这个答案:"想象一下,你必须在Java中用大约10亿个整数解决这个问题".我认为很明显,当OldEnthusiast说"非常快"时,他意味着很快就会出现大问题,即低复杂性.对于n = 1,这不是最有效的解决方案:`return false;`是;-) (3认同)
  • 所以你分配和清零500 MB的内存来解决n = 10000的这个问题? (2认同)

dan*_*ben 6

  1. 这是对的; 你的算法将在O(n lg n)时间内运行.

  2. 有一个更好的解决方案:您计算diff的逻辑是不正确的.无论a[i]是大于还是小于val,你仍然需要差异val - a[i].


Ita*_*man 5

这是使用哈希集的O(n)解决方案:

  public static boolean test(int[] a, int val) {
      Set<Integer> set = new HashSet<Integer>();

      // Look for val/2 in the array
      int c = 0;
      for(int n : a) {
        if(n*2 == val)
          ++c
      }
      if(c >= 2)
         return true; // Yes! - Found more than one

      // Now look pairs not including val/2
      set.addAll(Arrays.asList(a));
      for (int n : a) {
         if(n*2 == val)
            continue;
         if(set.contains(val - n))
            return true;
      }

      return false;
   }
Run Code Online (Sandbox Code Playgroud)

  • 如果我现在回答你的评论没有意义怎么办?你觉得这个讨论会在哪里得到吗?为了澄清:HashSet提供O(1)查找的证据假定哈希值的良好分布,这取决于您的输入.如果输入中的所有数字都在hashSet中获得相同的桶,则HashSet将非常慢(java.util.HashSet使用LinkedList来保存存储桶的内容).通常,您的输入将很好地分发,但并非总是如此.因此,hashSet不保证最坏情况下的查找复杂性. (4认同)
  • @danben:我明白;但是,当他们在算法类的问题中没有陈述*“最坏情况”、* *“平均情况”*或*“最佳情况”*时,总是隐含地理解问题是在要求* “最坏情况。”*这个答案在平均情况下非常好,但在最坏情况下则不然,这就是混乱的根源,因为OP没有明确说出其中之一。 (2认同)