以Leetcode704为例,题目:
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
示例 1:
输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4
示例 2:
输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1
提示:
你可以假设 nums 中的所有元素是不重复的。
n 将在 [1, 10000]之间。
nums 的每个元素都将在 [-9999, 9999]之间。
先介绍两种使用递归的方法,本质是一种,区别是假设target出现在【left,right】还是【left,right)中。
注意:使用递归进行二分查找要先用find或者count判断target是否在vector中,否则当target不在vector中时返回的值是将target插入vector中的位置下标-1。如:
vector<int> nums{-1, 0, 3, 5, 9, 12};
int target = 10;
运行结果为:4
更简单的方法我再想想,也欢迎给我建议和相互讨论。
递归完整代码如下:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
//方法一 利用迭代器 左闭右开
class Solution{
public:
int search(vector<int> &nums, int target)
{
if (nums.size() == 0 || count(nums.begin(),nums.end(),target)==0)
{
return -1;
}
int r = nums.size();
int l = 0;
if (r >= l)
{
int mid = (r - l) / 2;
if (nums[mid] == target)
{
return mid;
}
vector<int>::const_iterator first = nums.begin();
vector<int>::const_iterator last = nums.end();
vector<int> b;
if (nums[mid] > target) //左边找
{
b.assign(first, first + mid );
return search(b, target) ;
}
else { //在右边找
b.assign(first + mid , last);
return search(b, target)+ mid ;
}
}
return -1;
}
};
//方法2 迭代器 左闭右闭
class Solution{
public:
int search(vector<int> &nums, int target){
if (nums.size() == 0 || count(nums.begin(),nums.end(),target) ==0) {
return -1;
}
int r = nums.size() - 1;
int l = 0;
if (r >= l)
{
int mid = (r - l) / 2;
if (nums[mid] == target)
{
return mid;
}
else if (nums[mid] < target) //找右边
{
vector<int> b;
b.assign(nums.begin() + mid + 1 , nums.end());
return search(b, target) + mid + 1;
}
else{ //找左边
vector<int> b;
b.assign(nums.begin(), nums.begin() + mid);
return search(b, target);
}
}
return -1;
}
};
注意,vector的assign方法是左闭右开的,如:
//使用常量i遍历vector
int main()
{
vector<int> nums{-1, 0, 3, 5, 9, 12};
vector<int>::const_iterator first = nums.begin();
vector<int>::const_iterator last = nums.end();
vector<int> b;
b.assign(first, first + 2);
for (int i = 0; i < b.size();i++)
{
cout << b[i] <<'\n';
}
以上代码输出为:
-1
0
begin()返回的是第一个元素的迭代器,end()返回的是最后一个元素的再下一个元素的迭代器,且略微修改程序后运行、end()返回的值不一定相同。因此,遍历容器时,判定条件应为i<v.end()。如:
//使用迭代器i遍历vector
int main()
{
vector<int> nums{-1, 0, 3, 5, 9, 12};
vector<int>::const_iterator first = nums.begin();
vector<int>::const_iterator last = nums.end();
for (; first < nums.end();)
{
first++;
cout << *first << '\n';
if (first == last){
cout << *first << ',' << * last << '\n';
break;
}
}
}
以上代码输出为:
0
3
5
9
12
-1816858536
-1816858536,-1816858536
调换一下for循环下前两行代码的顺序:
//使用迭代器i遍历vector
int main()
{
vector<int> nums{-1, 0, 3, 5, 9, 12};
vector<int>::const_iterator first = nums.begin();
vector<int>::const_iterator last = nums.end();
for (; first < nums.end();)
{
cout << *first << '\n';
first++;
if (first == last){
cout << *first << ',' << * last << '\n';
break;
}
}
}
以上代码输出为:
-1
0
3
5
9
12
-1938122950,-1938122950
下面再介绍两种非递归的方法。
//方法一
//非递归,[left,right]左闭右闭区间
int search(vector<int> &nums, int target)
{
if (nums.size() == 0)
{
return -1;
}
int left = 0;
int right = nums.size() - 1; //right代表vector最后一个元素下标
int mid = (right - left) / 2;
if (nums[mid] == target)
{
return mid;
}
//若若容器中仅有一个元素,即left == right, 那么mid == left == right ,上面的if语句已经验证过了,所以下面while循环的判定语句不需要加=号
while (left < right) //[left,right]左闭右闭区间,left = right -1时依然成立。
{
if (nums[mid] < target)
{
left = mid + 1;
mid = left + (right - left) / 2;
}
else
{
right = mid - 1;
mid = left + (right - left) / 2;
}
if (nums[mid] == target)
{
return mid;
}
}
return -1;
}
//方法二
//非递归,[left,right)左闭右开区间
int search(vector<int> &nums, int target) {
if (nums.size() == 0)
{
return -1;
}
int left = 0;
int right = nums.size(); //right代表vector最后一个元素下标+1
int mid = (right - left) / 2;
if (nums[mid] == target)
{
return mid;
}
//若容器中仅有一个元素,即left == right-1, 那么mid == left == right-1 ,上面的if语句已经验证过了,所以下面while循环的判定语句不需要加=号
while (left < right - 1) //[left,right)左闭右开区间,=时不成立;若容器内仅有一个元素则会出现【1,1)的情况,所以left == right -1时不应该进入循环
{
if (nums[mid] < target) //找右边,[mid+1,right)
{
left = mid + 1;
mid = left + (right - left) / 2;
}
else //找左边,[left,mid)
{
right = mid ;
mid = left + (right - left) / 2;
}
if (nums[mid] == target)
{
return mid;
}
}
return -1;
}