我们紧接着上一篇博客中讲到的,分别利用循环和递归两种方法查找数组中的某个元素。首先利用循环来解决这个问题:
int Find(const vector<int>& vec, int n, int val)
{
int pos = -1;
for (int i = 0; i < n; i++)
{
if (vec[i] == val)
{
pos = i;
break;
}
}
return pos;
}
当我们用递归方法来解决时:
int Find(const vector<int>& vec, int n, int val)
{
if (n > 0)
{
if (vec[n - 1] == val)
{
return n - 1;
}
else
{
return Find(vec, n - 1, val);
}
}
}
但是我们仔细分析程序,当n的值为0时,这个程序就没有相应的返回值返回了,所以我们将程序再修改成如下形式:
int Find(const vector<int>& vec, int n, int val)
{
int pos = -1;
if (n > 0)
{
if (vec[n - 1] == val)
{
pos = n - 1;
}
else
{
pos = Find(vec, n - 1, val);
}
}
return pos;
}
对于上面这个程序我们还可以进行代码优化,可以充分利用“||”的特性:
int Find(const vector<int>& vec, int n, int val)
{
if (n < 1 || vec[n - 1] == val)
{
return n - 1;
}
else
{
return Find(vec, n - 1, val);
}
}
当数组中的元素是排列有序的时候(也就是按从小到大或者从大到小排好序的),我们可以利用折半查找或者二分查找的方法来查询某个元素。首先我们用循环来写二分查找的代码:
int HalfFind(const vector<int>& vec, int val)
{
int left = 0, right = vec.size() - 1;
int pos = -1;
while (left <= right)//1
{
int mid = (left + right) / 2;//2
//int mid = (right-left)/2+left;//解决相加范围过大的问题
if (val < vec[mid])
{
right = mid - 1;
}
else if (val > vec[mid])
{
left = mid + 1;
}
else
{
pos = mid;
break;
}
}
return pos;
}
这段程序中我们需要注意两个地方,第一个就是循环里面的条件,因为当left==right时,问题的规模就变成了1,也是需要查找的。第二个要注意的就是整型(int)的范围,当执行left+right时很有可能超过整型所能表示的范围,在面试的时候很有可能会问到这个地方。
当一个数组里有多个重复的元素时,若题目要求我们查询最左边的元素或者最右边的元素,如下所示:
此时,我们就需要对上面写的二分查找的代码进行改进,一定要注意数组越界,写条件的时候一定要测试几组测试用例:
int HalfFind(const vector<int>& vec, int val)
{
int left = 0, right = vec.size() - 1;
int pos = -1;
while (left <= right)
{
int mid = (left + right) / 2;
if (val < vec[mid])
{
right = mid - 1;
}
else if (val > vec[mid])
{
left = mid + 1;
}
else
{
while (mid > 0 && vec[mid - 1] == val)//最左查找
{
mid--;
}
while (mid <= vec.size()-2 && vec[mid + 1] == val)//最右查找
{
mid++;
}
pos = mid;
break;
}
}
return pos;
}
二分查找的递归代码如下所示:
int HalfFind(const vector<int>& vec, int left, int right, int val)
{
int pos = -1;
if (left <= right)
{
int mid = (right - left) / 2 + left;
if (vec[mid] > val)
{
pos = HalfFind(vec, left, mid - 1, val);
}
else if (vec[mid] < val)
{
pos = HalfFind(vec, mid + 1, right, val);
}
else
{
while(mid > 0 && vec[mid - 1] == val)//最左查找
{
mid--;
}
pos = mid;
}
}
return pos;
}
斐波那契数列的循环方法:时间复杂度为O(n),空间复杂度为O(1)。
int Fibon(int n)
{
int f1 = 1, f2 = 1, f3 = 1;
for (int i = 3; i <= n; i++)
{
f3 = f1 + f2;
f1 = f2;
f2 = f3;
}
return f3;
}
斐波那契数列的递归方法:时间复杂度为O(2^n),空间复杂度为O(log2n)。
int Fibon1(int n)
{
if (n <= 2)
{
return 1;
}
else
{
return Fibon1(n - 1) + Fibon1(n - 2);
}
}
斐波那契数列时间复杂度和空间复杂度分析: