如何在线性时间内找到2和?

时间:2018-06-10 10:27:46

标签: java arrays algorithm sorting data-structures

我参加了Coursera的Algorithms, Part II课程,其中一个面试问题(未评级)如下:

  

2-总和即可。给定a n个64位整数和目标值T的数组i,   确定是否有两个不同的整数ja[i] + a[j] = T   T - a[i]。您的算法应该在最差的线性时间内运行   情况下。

     

提示:按线性时间对数组进行排序。

我可以想到以几种方式解决它:

  1. 一次性将元素插入哈希表中。然后进行第二遍,在哈希表中查找i。空间复杂度对于哈希表是O(n),对于2遍是O(n)。该解决方案符合问题中陈述的时间要求。

  2. 对数组进行排序,然后分别从开头和结尾运行2个指针ja[i] + a[j] = T,寻找a[i] + a[j] < T。如果i,则递增j,否则递减long。空间复杂性取决于排序算法;假设,快速排序,无需额外空间。时间复杂度,nlogn,因此它没有达到问题中所述的时间要求。

  3. 考虑到在Radix Sort讲座后提出的问题,我假设其目的是使用其中一个Radix排序。由于问题指定了64位整数,使用return redirect('dashboard')->with('status', 'Profile updated!'); 的二进制表示,并使用In-place MSD radix sort,因此可以在线性时间内就地对数组进行排序。这似乎是最好的方法。

  4. 其他想法?

    P.S。我已经看到了这个question,但是它假定了一个排序的数组,并且那里的所有答案都使用了某种散列。

    我也看过这个question,但对于2-sum的特定情况,它似乎过于复杂。

3 个答案:

答案 0 :(得分:2)

我分析了您的观察结果以及似乎符合要求的观察结果:

  

一次性将元素插入哈希表中。然后做第二遍,   在哈希表中寻找T - a [i]。空间复杂度为O(n)   哈希表,以及2次传递的O(n)。这个解决方案符合   问题中陈述的时间要求。

我认为这种方法不符合要求,因为hashtable最坏情况插入复杂度理论上是O(n)。

正如你所说,你研究过Radix Sort,我相信这是可行的方法,你可以在时间要求内对数组进行排序,之后你可以使用Two Pointers技术检查是否有总和{ {1}}:

T

答案 1 :(得分:0)

回答我自己的问题,这是Java中的工作解决方案:

public class RadixSortsInterviewQuestions {
    private static final int MSB = 64;

    static Map.Entry<Integer, Integer> twoSum(long[] a, long sum) {
        int n = a.length - 1;
        sort(a, MSB, 0, n);

        for (int i = 0, j = n; i < j; ) {
            long t = a[i] + a[j];
            if (t == sum) {
                return new SimpleImmutableEntry<>(i, j);
            } else if (t < sum) {
                i++;
            } else {
                j--;
            }
        }
        return null;
    }

    // Binary MSD radix sort: https://en.wikipedia.org/wiki/Radix_sort#In-place_MSD_radix_sort_implementations
    private static void sort(long[] a, int d, int lo, int hi) {
        if (hi < lo || d < 1) return;

        int left = lo - 1;
        int right = hi + 1;

        for (int i = left + 1; i < right; ) {
            if (isBitSet(a[i], d)) {
                swap(a, i, --right);
            } else {
                left++;
                i++;
            }
        }
        sort(a, d - 1, lo, left);
        sort(a, d - 1, right, hi);
    }

    private static boolean isBitSet(long x, int k) {
        boolean set = (x & 1L << (k - 1)) != 0;

        // invert signed bit so that all positive integers come after negative ones
        return (k == MSB) != set;
    }

    private static void swap(long[] a, int i, int j) {
        long tmp = a[i];
        a[i] = a[j];
        a[j] = tmp;
    }
}

答案 2 :(得分:-1)

在遍历数组时,将值放入哈希值,将值映射到索引。由于我们只查找两个数字的总和,因此请查找当前数字和哈希值中的余数之和以获得目标。

public static int[] twoSumInOnePass(int[] values, int target) throws Exception {
    // value => index
    Map<Integer, Integer> valueToIndexMap = new HashMap<Integer, Integer>();
    for (int i = 0; i < values.length; i++) {
        int remainder = target - values[i];
        if (valueToIndexMap.containsKey(remainder)) {
            return new int[] { valueToIndexMap.get(remainder), i };
        }
        valueToIndexMap.put(values[i], i);
    }

    throw new Exception("Could not find indexes that sum to " + target);
}

https://leetcode.com/problems/two-sum/description/