【Leetcode】33. 搜索旋转排序数组

149 阅读1分钟

题目描述

在这里插入图片描述

// 33. 搜索旋转排序数组


// 整数数组 nums 按升序排列,数组中的值 互不相同 。

// 在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)
// 上进行了 旋转,使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0]
// , nums[1], ..., nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7]
// 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。

// 给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target
// ,则返回它的索引,否则返回 -1 。

题解

// 这个题想到二分查找不难,但是能把边界条件分清楚写清楚就不简单了。
// 分析旋转后的排序如下:
// ========================== 旋转后的排序情况 =======================
// 没有旋转的原数组[1,2,3,4,5,6,7]mid = 3
// 旋转后:
// 一,nums[mid]比nums[left]小 - [6,7,0,1,2,4,5]型:
//	 1.target在mid右边 - (target比nums[mid]大 && 比nums[right]小或相等);
//	 2.target在mid左边 - target比nums[mid]; 
//					   - (target比nums[mid]大 && 比nums[left]大);

// 二,nums[mid]比nums[left]大 - [2,4,5,6,7,0,1]型:
//	 1.target在mid右边 - (target比nums[mid]小 && 比nums[left]小); 
// 					   -  target比nums[mid];
// 	 2.target在mid左边 - (target比nums[mid]小 && 比nums[left]大或相等);
// ===================================================================

// 可以看到,当nums[mid]比nums[left]小时,数组为[6,7,0,1,2,4,5]型,
// target在mid右边只有1种情况,而target在mid左边时,有2种情况,
// 那我们可以只在if中讨论target在mid右边的条件,
// 剩下的其他情况都属于target在mid左边的时候,留给else即可。这样可以大大缩短
// 代码量。其他情况则同理。
// 
// 排除特殊情况,之后初始化左右指针left和right。
// while循环开始二分查找,中点为mid = (left + right) / 2,如果nums[mid]等于target
// 直接返回mid。如果不是,则直接按照我们上面分析旋转后的排序情况进行if-else条件判断。
// 直到找到nums[mid] == target,或者left和right指针相遇(left = right),while循环
// 停止,说明没找到target,返回-1。
// 
// 执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
// 内存消耗:37.9 MB, 在所有 Java 提交中击败了53.93%的用户
class Solution {
    public int search(int[] nums, int target) {
        int len = nums.length;
		if (len == 0) return -1;
		if (len == 1)
			return (nums[0] == target) ? 0 : -1;
			
        int left = 0, right = len - 1;
        while (left <= right) {
            int mid = (left + right) / 2;
			if (nums[mid] == target)
				return mid;
			
			if (nums[left] > nums[mid]) {
				if (nums[mid] < target && target <= nums[right])
					left = mid + 1;
				else 
					right = mid - 1;
			}
			else {  // nums[left] <= nums[mid]
				if (target < nums[mid] && nums[left] <= target) 
					right = mid - 1;
				else 
					left = mid + 1;
			}
        }
        return -1;
    }
}