说有一个数组[1、2、9、4,-5,-4],我们需要找出是否有2个数字总和为0。时间复杂度应为O(n),且仅是常数应该使用额外的空间。允许修改原始数组。
我将其作为面试问题,但没有弄清楚如何解决。谢谢。
答案 0 :(得分:1)
如果我们知道数组的数字范围,则可以创建一个哈希图,该哈希图将消耗恒定的额外空间来解决O(n)时间复杂度的问题。
#include <iostream>
#include <cmath>
using namespace std;
int main(){
int arr[]={1, 2, 9, 4, -5, -4};
int n = sizeof(arr)/sizeof(arr[0]);
const int N=1000001; // the maximum non negative value for arr[i] is 1,000,000
int hashmap [N];
bool found=false;
for (int i=0; i<N; i++){ //initialize the hashmap
hashmap[i]=0;
}
for (int i=0; i<n; i++){
int temp = abs( arr[i] );
if ( hashmap[ temp ] == 0 ){ // no collision
if (arr[i] >= 0){
hashmap[ temp ] = 1; //mark the hashmap 1 for positive arr[i]
}else{
hashmap[ temp ] = -1; //mark the hashmap -1 for negative arr[i]
}
}else{ //collision
if (hashmap[ temp ] == 1 && arr[i] <= 0){
found = true;
break;
}else if (hashmap[ temp ] == -1 && arr[i] > 0){
found = true;
break;
}
}
}
if (found){
cout << "Found" << endl;
}else{
cout << "Not found" << endl;
}
return 0;
}
答案 1 :(得分:1)
一般评论:
如果我们可以修改原始数组,并且对数组中的值的大小没有限制,则可以在数组的每个元素中存储尽可能多的信息。
参见https://en.wikipedia.org/wiki/Gödel_numbering
在这种特殊情况下,您可以更轻松地完成操作。
我们只需要知道一个值及其负值是否同时存在于数组中就可以像这样完成:
a :=
是数组中最大的数字。
b :=
数组中最小的负数。
bits := 2 * max(a,-b)
让m
是一个具有bits
位的整数变量。 (均以0初始化)
// Now we read the array (time **O(n)**).
for(i=0; n>i; i++){
if(0<=a[n]){
if(m.testBit(2*a[n] + 1))
return true; // negative value was already there
m.setBit(2*a[n]);
}
else{
if(m.testBit(2*a[-n]))
return true; // positive value was already there
m.setBit(2*(-n) + 1);
}
return false;
如果我们使用第一个数组元素来存储m
(第一次设置m后就不再需要原始值),则它不会占用额外的空间。
但这是一种作弊,因为我们需要数组元素具有足够的位。
但是我们只用了O(n)时间,根本没有多余的空间。