[C++] leetcode704的递归和非递归解法,递归用到assign方法进行vector的切片

以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;
        }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值