题目:输入一个已经按升序排序过的数组和一个数字,在数组中查找两个数,使得它们的和正好是输入的那个数字。要求时间复杂度是O(n)。如果有多对数字的和等于输入的数字,输出任意一对即可。
例如输入数组1、2、4、7、11、15和数字15。由于4+11=15,因此输出4和11。
解题思路:
最初我们找到数组的第一个数字和最后一个数字。当两个数字的和大于输入的数字时,把较大的数字往前移动;当两个数字的和小于数字时,把较小的数字往后移动;当相等时,打完收工。这样扫描的顺序是从数组的两端向数组的中间扫描。
代码如下:
public static boolean findTwoNumbers(int[] data,int expectsum)
{
boolean found = false;
if(data==null)
{
return false;
}
int begin=0;
int end=data.length-1;
while(begin<end)
{
int cursum=data[begin]+data[end];
if(cursum<expectsum)
{
begin++;
}
else if(cursum>expectsum)
{
end--;
}
else
{
found=true;
num1=data[begin];
num2=data[end];
return found;
}
}
return found;
}
扩展:
题目:如果输入的数组是没有排序的,但知道里面数字的范围,其他条件不变,如和在O(n)时间里找到这两个数字?
解题思路:
(1)由于知道数的范围,可以采用hash表,扫描一遍数组将hashTable[data[i]]=1.
(2)再扫描一遍数组,对每个数进行hashTable[sum-data[i]]==1。
代码如下:
public static boolean findTwoNumbers(int[] data,int expectsum, int range)
{
boolean found = false;
int[] hashTable = new int[2*range];
java.util.Arrays.fill(hashTable, 0);
for(int i=0;i<data.length;i++)
{
hashTable[data[i]]=1;
}
for(int i=0;i<data.length;i++)
{
if(hashTable[expectsum-data[i]]==1)
{
found=true;
num1=data[i];
num2=expectsum-data[i];
return found;
}
}
return found;
}