Letcode33. Search in Rotated Sorted Array

Letcode33. Search in Rotated Sorted Array

Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.(i.e., [0,1,2,4,5,6,7] might become [4,5,6,7,0,1,2]).
You are given a target value to search. If found in the array return its index, otherwise return -1.
You may assume no duplicate exists in the array.
Your algorithm’s runtime complexity must be in the order of O(log n).

Example 1:

Input: nums = [4,5,6,7,0,1,2], target = 0
Output: 4

Example 2:

Input: nums = [4,5,6,7,0,1,2], target = 3
Output: -1
解法一

1.根据首尾判断是否旋转
2.若未旋转,直接二分查找(注意:可以直接判断target是否在首尾之内,否则直接返回-1)
3.若旋转,先找旋转点(以找到最大值为例)
(1)情况一:target[0,index_max]之内:此范围二分查找
(2)情况二:target[index_max+1,len(nums)-1]之内:此范围二分查找
(3)情况三:若不在以上两种情况则直接返回-1

解法二

将题目中的数组分成两段,一段是[4,5,6,7],另一段[0,1,2](特殊情况[1,2,3,4]可以分为[1,2,3,4]和[])。
对于target不在的那一段,我们将它设置为无穷大,这样整个数组有序,可以用正常的二分法去找 target 了,例如

[ 4 5 6 7 1 2 3] ,如果 target = 5,那么数组可以看做 [ 4 5 6 7 inf inf inf ]。
[ 4 5 6 7 1 2 3] ,如果 target = 2,那么数组可以看做 [ -inf -inf - inf -inf 1 2 3]。

每次只关心 mid 的值,所以 mid 的取值为{nums [ mid ], inf, -inf}

  • 判断 nums [ mid ]target 不在同一段:把 nums [ mid ]target 同时与 nums [ 0 ] 比较,如果它俩都大于 nums [ 0 ] 或者都小于 nums [ 0 ],那么就代表它俩在同一段。
  • mid = nums[mid]nums [ mid ]target 在同一段里边。
  • mid = infnums [ mid ]target 不在同一段里边,且target < nums[0](例如[4,5,6,7,1,2,3], target = 2)
  • mid = infnums [ mid ]target 不在同一段里边,且target > nums[0](例如[5,6,7,1,2,3,4], target = 6)

时间复杂度: O ( l o g n ) O(logn) O(logn)
空间复杂度: O ( 1 ) O(1) O(1)

解法三

算法基于一个事实,数组从任意位置劈开后,至少有一半是有序的。我们可以先找到哪一段是有序的 (只要判断端点即可),然后看 target 在不在这一段里,如果在,那么就把另一半丢弃。如果不在,那么就把这一段丢弃。

比如 [ 4 5 6 7 1 2 3] ,从 7 劈开,左边是 [ 4 5 6 7] 右边是 [ 7 1 2 3],左边是有序的。

时间复杂度: O ( l o g n ) O(logn) O(logn)
空间复杂度: O ( 1 ) O(1) O(1)

Java
public int search(int[] nums, int target) {//解法二
    int lo = 0, hi = nums.length - 1;
    while (lo <= hi) {
        int mid = lo + (hi - lo) / 2;
        int num = nums[mid]; 
        //nums [ mid ] 和 target 在同一段
        if ((nums[mid] < nums[0]) == (target < nums[0])) {
            num = nums[mid];
        //nums [ mid ] 和 target 不在同一段,同时还要考虑下变成 -inf 还是 inf。
        } else {
            num = target < nums[0] ? Integer.MIN_VALUE : Integer.MAX_VALUE;
        }
		//正常二分
        if (num < target)
            lo = mid + 1;
        else if (num > target)
            hi = mid - 1;
        else
            return mid;
    }
    return -1;
}
public int search(int[] nums, int target) {//解法三
		int start = 0;
		int end = nums.length - 1;
		while (start <= end) {
			int mid = (start + end) / 2;
			if (target == nums[mid]) {
				return mid;
			}
            //左半段是有序的
			if (nums[start] <= nums[mid]) {
                //target 在这段里
				if (target >= nums[start] && target < nums[mid]) {
					end = mid - 1;
				} else {
					start = mid + 1;
				}
            //右半段是有序的
			} else {
				if (target > nums[mid] && target <= nums[end]) {
					start = mid + 1;
				} else {
					end = mid - 1;
				}
			}

		}
		return -1;
	}
C++
int search(vector<int>& nums, int target) {//解法二
    int lo = 0, hi = nums.size();//左右各一个指针
    while (lo < hi) {
        int mid = (lo + hi) / 2;//找出中间点
        double num = (nums[mid] < nums[0]) == (target < nums[0])//如果nums[mid]和target在nums[0]的同侧
                   ? nums[mid]
                   : target < nums[0] ? -INFINITY : INFINITY;
                   
        if (num < target)
            lo = mid + 1;
        else if (num > target)
            hi = mid;
        else
            return mid;
    }
    return -1;
}
Python
class Solution: #解法一
    def search(self, nums: List[int], target: int) -> int:
        if len(nums)<1:return -1
        #二分查找
        def two_find(m,n):
            if m>n:return -1
            mid = (m+n)//2
            if nums[mid]==target:
                return mid
            elif nums[mid]>target:
                return two_find(m,mid-1)
            else:return two_find(mid+1,n)
        #找旋转点,返回最大值处
        def find_max(m,n):
            mid = (m+n)//2
            if nums[mid]>nums[mid+1]:return mid
            elif nums[mid]>=nums[0]:return find_max(mid+1,n)
            else: return find_max(m,mid-1)
        
        if nums[0]<=nums[-1]:#如果数组没有旋转!("="是为了在nums长度为1时也能算进此)
            if target>=nums[0] and target<=nums[-1]:return two_find(0,len(nums)-1)
            else:return -1
        else:
            index_max = find_max(0,len(nums)-1)
            if target>=nums[0] and target<=nums[index_max]:return two_find(0,index_max)
            elif target>=nums[index_max+1] and target<=nums[len(nums)-1]:return two_find(index_max+1,len(nums)-1)
            else:return -1

参考
leetcode题解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值