LeetCode 搜索旋转排序数组(二分搜索)

这篇博客探讨了如何在已知旋转的升序数组中,以O(log n)的时间复杂度找到目标值的索引。通过分析示例,提出了两种解决方案:一种是利用数组的两部分递增特性进行查找,另一种是使用map记录值与下标的映射。最后,作者提到了一种类似于二分搜索的高效算法,对这种算法表示赞赏。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

假设按照升序排序的数组在预先未知的某个点上进行了旋转。

( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。

搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。你可以假设数组中不存在重复的元素。你的算法时间复杂度必须是 O(log n) 级别。

示例 1:
输入: nums = [4,5,6,7,0,1,2], target = 0
输出: 4

示例 2:
输入: nums = [4,5,6,7,0,1,2], target = 3
输出: -1

思路分析:观察旋转后的数组,不难发现,数组被分为两部分,且两部分都是从左至右递增,那么,寻找的时候也可以分两部分进行查找
在这里插入图片描述

int search(vector<int>& nums, int target) {
	int numsLength = nums.size();
	if (numsLength == 0){
		return -1;
	}
	if (nums[0] <= target){//从起始位置出发.此位置是左半部分最小的,只有target大于等于它,才可能在此部分寻找到
		int index = 0;
		while (index < numsLength && nums[index] < target){//增加下标,直到nums[index]不小于target
			++index;
		}
		if (index < numsLength && nums[index] == target){//下标合法,且寻找到了
			return index;
		}
	}
	else if (nums[numsLength - 1] >= target){//从尾端位置出发,此位置为右半部分最大的,必须要小于等于它,才可能在此处寻找到
		int index = numsLength - 1;
		while (index >= 0 && nums[index] > target){//减小下标,直到nums[index]不大于target
			--index;
		}
		if (index >= 0 && nums[index] == target){//下标合法,且寻找到了
			return index;
		}
	}
	return -1;//否则直接返-1
}

在这里插入图片描述
方法二:利用map容器,将值与下标进行标记

int search(vector<int>& nums, int target) {
	int numsLength = nums.size();
	map<int, int> numsIndexM;//numsIndexM[nums[index]] = index,将值与下标标记
	for (int index = 0; index < numsLength; ++index){
		numsIndexM[nums[index]] = index;
	}
	if (numsIndexM.count(target) != 0){//如果包含,返回下标
		return numsIndexM[target];
	}
	else{
		return -1;
	}
}

在这里插入图片描述
还是8ms,那么证明主流解法并不是这个。。。
翻阅评论区,发现一种类似二分法的算法

class Solution {
public:
	int search(vector<int>& nums, int target) {
		int numsLength = nums.size();
		int left = 0;//左指针
		int right = numsLength - 1;//右指针
		int mid;//中间下标
		while (left <= right) {
			mid = (left + right) / 2;
			if (nums[mid] == target) {
				//找到了,返回
				return mid;
			}
			//左半边是正常序列
			if (nums[left] <= nums[mid]) {
				//如果target在这个序列
				if (target >= nums[left] && target <= nums[mid]) {
					//定位到左半边
					right = mid - 1;
				}
				else {
					//定位到右半边
					left = mid + 1;
				}
			}
			else {
				//右半边是正常序列
				//如果target在这个序列
				if (target >= nums[mid] && target <= nums[right]) {
					//定位到右半边
					left = mid + 1;
				}
				else {
					//定位到左半边
					right = mid - 1;
				}
			}
		}
		return -1;
	}
};

在这里插入图片描述
将半边有序、半边无序运用的淋漓尽致,膜拜!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值