美文网首页
0033. 搜索旋转排序数组

0033. 搜索旋转排序数组

作者: 蓝笔头 | 来源:发表于2021-08-19 09:11 被阅读0次

    题目地址

    https://leetcode-cn.com/problems/search-in-rotated-sorted-array/

    题目描述

    给你一个升序排列的整数数组 nums ,和一个整数 target 。
    
    假设按照升序排序的数组在预先未知的某个点上进行了旋转。(例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
    
    请你在数组中搜索 target ,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。
    
    
    示例 1:
    
    输入:nums = [4,5,6,7,0,1,2], target = 0
    输出:4
    示例 2:
    
    输入:nums = [4,5,6,7,0,1,2], target = 3
    输出:-1
    示例 3:
    
    输入:nums = [1], target = 0
    输出:-1
    
    
    提示:
    
    1 <= nums.length <= 5000
    -10^4 <= nums[i] <= 10^4
    nums 中的每个值都 独一无二
    nums 肯定会在某个点上旋转
    -10^4 <= target <= 10^4
    

    题解

    不按套路出牌

    class Solution {
        public int search(int[] nums, int target) {
            for (int i = 0; i < nums.length; ++ i) {
                if (target == nums[i]) {
                    return i;
                }
            }
            return -1;
        }
    }
    

    时间复杂度:O(n),n 为数组 nums 的长度。

    过了,再次证明了 leetcode 的执行用例不够完善。

    二分搜索

    看到关键词:数组O(log n) 就应该想到二分搜索。

    二分搜索的前提是数组有序,旋转后的排序数组可能看成两个有序的数组:

    • (1) [nums[k], nums[k+1], ..., nums[n-1]
    • (2) nums[0], nums[1], ..., nums[k-1]]

    原数组按升序排列,nums[0] 是其最小值,所以我们第一步应该找到 nums[0],也就是最小值所在的位置。
    这样就可以把旋转后的数组分成两个有序的数组。

        public int getMinValueIndex(int[] nums) {
            int left = 1;
            int right = nums.length - 1;
            while (left < right) {
                // 因为 nums.length <= 50000,所以 (left + right) 不会溢出
                // 担心溢出可以通过以下方式计算 middle 索引
                // left + (right - left) / 2
                int middle = (left  + right) / 2;
    
                
                if (nums[middle] > nums[0]) {
                    // 大于第一个数,说明处于第一个有序数组的范围,要向右移动 left
                    left = middle + 1;
                } else if (nums[middle] < nums[0]){
                    // 小于第一个数,说明处于第二个有序数组的范围,要向左移动 right
                    right = middle;
                }
            }
    
            // left == right
            return nums[0] < nums[right] ? 0 : right;
        }
    

    注意:搜索的范围是 [1, length - 1],没有搜索位置 0

    完整代码如下所示:

    class Solution {
        public int search(int[] nums, int target) {
            int minValueIndex = getMinValueIndex(nums);
            
            // case 1
            // 没有旋转为两个有序数组,还是一个有序数组
            if (minValueIndex == 0) {
                return binarySearch(nums, 0, nums.length - 1, target);
            }
    
            // case 2
            // target 处于第一个有序数组的范围
            if (target >= nums[0]) {
                return binarySearch(nums, 0, minValueIndex - 1, target);
            }
    
            // case 3
            // target 处于第二个有序数组的范围
            return binarySearch(nums, minValueIndex, nums.length - 1, target);
        }
    
        public int binarySearch(int[] nums, int left, int right, int target) {
            while (left <= right) {
                int middle = (left + right) / 2;
                if (nums[middle] == target) {
                    return middle;
                } else if (nums[middle] < target) {
                    left = middle + 1;
                } else {
                    right = middle - 1;
                }
            }
    
            return -1;
        }
    
        public int getMinValueIndex(int[] nums) {
            int left = 1;
            int right = nums.length - 1;
            while (left < right) {
                // 因为 nums.length <= 50000,所以 (left + right) 不会溢出
                // 担心溢出可以通过以下方式计算 middle 索引
                // left + (right - left) / 2
                int middle = (left  + right) / 2;
    
                
                if (nums[middle] > nums[0]) {
                    // 大于第一个数,说明处于第一个有序数组的范围,要向右移动 left
                    left = middle + 1;
                } else if (nums[middle] < nums[0]){
                    // 小于第一个数,说明处于第二个有序数组的范围,要向左移动 right
                    right = middle;
                }
            }
    
            // left == right
            return nums[0] < nums[right] ? 0 : right;
        }
    }
    

    时间复杂度:O(log n),n 为数组 nums 的长度。

    相关文章

      网友评论

          本文标题:0033. 搜索旋转排序数组

          本文链接:https://www.haomeiwen.com/subject/cdkibltx.html