文章参考:http://blog.youkuaiyun.com/v_JULY_v/article/details/6419466
本文是基于上文链接的内容进行裁剪,在自己的理解层次上写出的文章。
第一节:寻找和为定值的两个数
题目描述
输入一个数组和一个数字,在数组中查找两个数,使得它们的和正好是输入的那个数字。
要求时间复杂度是O(N)。如果有多对数字的和等于输入的数字,输出任意一对即可。
例如输入数组1、2、4、7、11、15和数字15。由于4+11=15,因此输出4和11。
思路一:穷举法
从数组中任意选取两个数,判定它们的和是否为输入的那个数字。对每个a[i],查找sum-a[i]是否也在原始序列中,每一次要查找的时间都要花费为O(N),这样下来,最终找到两个数还是需要O(N^2)的复杂度。此举复杂度为O(N^2)。现在这是第一步,得到的最大时间复杂度。紧接着是要用各种方式去优化。
思路二:利用排序去优化
当我们对数组进行排序以后,再去查找,就可以利用各种有效的查找算法。这里,可以利用二分查找。可以将O(N)的查找时间提高到O(logN),这样对于N个a[i],都要花logN的时间去查找相对应的sum-a[i]是否在原始序列中,总的时间复杂度已降为O(N*logN),且空间复杂度为O(1)。
二分查找的实现,有两种定义:算法所操作的区间,是左闭右开区间,还是左闭右闭区间,这个区间,需要在循环初始化,循环体是否终止的判断中,以及每次修改left,right区间值这三个地方保持一致,否则就可能出错。
方式一:左闭右闭( left <= right,right = middle - 1)
int search(int array[], int n, int v)
{
int left, right, middle;
left = 0, right = n - 1;<span style="white-space:pre"> </span>//不同1
while (left <= right)<span style="white-space:pre"> </span>//不同2
{
middle = left + (right-left)/2;
if (array[middle] > v)
{
right = middle - 1;<span style="white-space:pre"> </span>//不同3
}
else if (array[middle] < v)
{
left = middle + 1;
}
else
{
return middle;
}
}
return -1;
}
方式二:左闭右开( left < right,right = middle;)
int search(int array[], int n, int v)
{
int left, right, middle;
left = 0, right = n;
while (left < right)
{
middle = left + (right-lef