我参加了Coursera的Algorithms, Part II课程,其中一个面试问题(未评级)如下:
2-总和即可。给定
a
n
个64位整数和目标值T
的数组i
, 确定是否有两个不同的整数j
和a[i] + a[j] = T
T - a[i]
。您的算法应该在最差的线性时间内运行 情况下。提示:按线性时间对数组进行排序。
我可以想到以几种方式解决它:
一次性将元素插入哈希表中。然后进行第二遍,在哈希表中查找i
。空间复杂度对于哈希表是O(n),对于2遍是O(n)。该解决方案符合问题中陈述的时间要求。
对数组进行排序,然后分别从开头和结尾运行2个指针j
和a[i] + a[j] = T
,寻找a[i] + a[j] < T
。如果i
,则递增j
,否则递减long
。空间复杂性取决于排序算法;假设,快速排序,无需额外空间。时间复杂度,nlogn,因此它没有达到问题中所述的时间要求。
考虑到在Radix Sort讲座后提出的问题,我假设其目的是使用其中一个Radix排序。由于问题指定了64位整数,使用return redirect('dashboard')->with('status', 'Profile updated!');
的二进制表示,并使用In-place MSD radix sort,因此可以在线性时间内就地对数组进行排序。这似乎是最好的方法。
其他想法?
P.S。我已经看到了这个question,但是它假定了一个排序的数组,并且那里的所有答案都使用了某种散列。
我也看过这个question,但对于2-sum的特定情况,它似乎过于复杂。
答案 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);
}