LeetCode81-搜索旋转排序数组 II

解决LeetCode81问题,探讨搜索旋转排序且可能包含重复元素的数组的方法。通过分析目标值(target)在旋转数组中的位置,使用双指针策略进行搜索。在有重复元素的情况下,确定指针移动策略的挑战在于无法仅凭边界元素判断中间元素所属的有序子数组。因此,需要调整指针同时向中间移动,以找到目标值。
摘要由CSDN通过智能技术生成

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

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

编写一个函数来判断给定的目标值是否存在于数组中。若存在返回 true,否则返回 false。

示例 1:

输入: nums = [2,5,6,0,0,1,2], target = 0
输出: true

示例 2:

输入: nums = [2,5,6,0,0,1,2], target = 3
输出: false

进阶:

  • 这是 搜索旋转排序数组 的延伸题目,本题中的 nums 可能包含重复元素。
  • 这会影响到程序的时间复杂度吗?会有怎样的影响,为什么?

一、思路

假设原来升序的数组是nums,当其经过一次旋转后,得到两个升序数组nums1和nums2,由这两个升序数组构成一个旋转数组nums_rotate,假设nums1在前

那么有: n u m s 1 [ 0 ] > = n u m s 2 [ n u m s 2. s i z e ( ) − 1 ] nums1[0] >= nums2[nums2.size() - 1] nums1[0]>=nums2[nums2.size()1]

在前面的那个数组nums1,其所有元素都大于或等于后面的数组nums2

利用这个性质可以对数组进行快速检索

(一)从target的位置开始考虑

我们知道target一定在两个数组中的一个,那么可以通过确定target的位置,来决定两边指针的移动方向。

设两个指针为lo与hi,中间的指针为mid

将数组划分为两个前一个大的数组为nums1,后一个小的数组为nums2

(1)假设target在nums1中

那么必然有: n u m s [ h i ] &lt; = t a r g e t nums[hi]&lt;=target nums[hi]<=target

(2)假设target在nums2中

那么必然有: n u m s [ l o ] &gt; = t a r g e t nums[lo]&gt;=target nums[lo]>=target

相比较于无重复的数组,有重复的最大问题是无法根据 n u m s [ l o ] nums[lo] nums[lo] n u m s [ h i ] nums[hi] nums[hi]来确定 n u m s [ m i d ] nums[mid] nums[mid]处在哪个数组,因此也无法制定移动策略

例如:

[1,1,5,1,1,1,1,1,1,1,1,1,1,1,1]
5

在这个例子中,我们只知道 n u m s [ m i d ] = 1 nums[mid]=1 nums[mid]=1,但是无法找出mid处于哪个有序数组

如果mid在前一个数组,那么应该改变lo

如果mid在后面的数组,那么应该改变hi

因为不知道是哪一种情况,所以同时改变lo与hi,向mid逼近

C++代码:

class Solution {
public:
	bool search(vector<int>& nums, int target) {
		if (nums.empty())
			return false;
		int lo = 0, hi = nums.size() - 1;
		int mid;
		while (lo <= hi) {
			mid = lo + ((hi - lo) >> 1);
			if (nums[mid] == target || nums[lo] == target || nums[hi] == target)
				return true;
			// 在前一个数组的情况
			if (target > nums[lo]) {
				if (target < nums[mid])	//target 在lo与mid之间
					hi = mid - 1;
				else {
					if (nums[mid] > nums[lo])	//target 在mid与hi之间
						lo = mid + 1;
					else if (nums[mid] < nums[lo])	//target 在lo与mid之间
						hi = mid - 1;
					else {
						if (nums[lo] == nums[hi]) {	//target 在lo与mid之间 或者是 mid与hi之间
							hi--;
							lo++;
						}
						else
							lo = mid + 1;			//target 在mid与hi之间
					}
				}
			}	// 在后一个数组的情况
			else if (target < nums[hi]) {
				if (target > nums[mid])	//target 在mid与hi之间
					lo = mid + 1;
				else {
					if (nums[mid] > nums[hi])	//target 在mid与hi之间
						lo = mid + 1;
					else if (nums[mid] < nums[hi])	//target 在lo与mid之间
						hi = mid - 1;
					else {
						if (nums[lo] == nums[hi]) {	//target 在lo与mid之间 或者是 mid与hi之间
							hi--;
							lo++;
						}
						else
							hi = mid - 1;			//target 在mid与hi之间
					}
				}
			}
			else
				return false;
		}
		return false;
	}
};

执行效率:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值