[LeetCode] 33. 搜索旋转排序数组

题目链接: https://leetcode-cn.com/problems/search-in-rotated-sorted-array/

题目描述:

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

( 例如,数组 [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

思路:

题目中说明要用O(log n)能想到就是二分法!

思路一:

整体思路:先用二分法找出最小值,也是那个分割点,例如[4,5,6,7,0,1,2],我们找出数字0;

接下来判断target是在分割点的左边还是右边;

最后再使用一次二分法找出target的位置. 所以时间复杂度为:\(O(logn)\)

只有一个难点,那就是如何通过二分法找出那个分割点呢?

就是和它的右端点比较判断,直接看代码吧!

思路二:

直接使用二分法,

判断那个二分点,有几种可能性

  1. 直接等于target

  2. 在左半边的递增区域

    a. targetleftmid 之间

    b.不在之间

  3. 在右半边的递增区域

    a. targetmidright 之间

    b. 不在之间

思路三:

参考链接1

参考链接2

还是很容易理解的!


关注我的知乎专栏,了解更多解题技巧,大家共同进步!

代码:

方法一:

python

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        if not nums:return -1
        n = len(nums)
        left = 0
        right = len(nums) - 1
        while left < right:
            mid = left + (right - left) //2
            if nums[mid] > nums[right]:
                left = mid + 1
            else:
                right = mid
        t = left
        left = 0
        right = len(nums) - 1
        while left <= right:
            mid = (left + right) //2
            realmid = (mid + t) % n
            if nums[realmid] == target:
                return realmid
            elif nums[realmid] > target:
                right = mid - 1
            else:
                left = mid + 1
        return -1

java

class Solution {
    public int search(int[] nums, int target) {
        if (nums == null || nums.length == 0) return -1;
        int left = 0;
        int right = nums.length - 1;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] > nums[right]) left = mid + 1;
            else right = mid;
        }
        //System.out.println(left);
        int split_t = left;
        left = 0;
        right = nums.length - 1;
        if (nums[split_t] <= target && target <= nums[right]) left = split_t;
        else right = split_t;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] == target) return mid;
            else if (nums[mid] > target) right = mid - 1;
            else left = mid + 1;
        }
        return -1;
        
    }
}

方法二

python

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        n = len(nums)
        if n == 0:
            return -1
        left = 0
        right = n - 1
        while left < right:
            mid = left + (right - left) // 2
            if nums[mid] == target:
                return mid
            elif nums[left] <= nums[mid]:
                if nums[left] <= target < nums[mid]:
                    right = mid - 1
                else:
                    left = mid + 1
            else:
                if nums[mid] < target <= nums[right]:
                    left = mid + 1
                else:
                    right = mid - 1
        #print(left,right)
        return left if nums[left] == target else -1

java

class Solution {
    public int search(int[] nums, int target) {
        if (nums == null || nums.length == 0) return -1;
        int n = nums.length;
        int left = 0;
        int right = n - 1;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] == target) return mid;
            else if (nums[left] <= nums[mid]) {
                if (nums[left] <= target && target < nums[mid]) right = mid - 1;
                else left = mid + 1;

            } else if (nums[mid] < nums[right]) {
                if (nums[mid] < target && target <= nums[right]) left = mid + 1;
                else right = mid - 1;
            } 
        }
        return nums[left] == target ? left : -1;
        
    }
}

思路三:

python

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        n = len(nums)
        if n == 0:
            return -1
        left = 0
        right = n 
        while left < right:
            mid = left + (right - left) // 2
            # if (target < nums[0] and nums[mid] < nums[0]) or \
            # (target > nums[0] and nums[mid] > nums[0])
            if (nums[mid] < nums[0]) == (target < nums[0]):
                num = nums[mid]
            else:
                if target < nums[0]:
                    num = float("-inf")
                else:
                    num = float("inf")
            if num < target:
                left = mid + 1
            elif num > target:
                right = mid
            else:
                return mid
        return -1

java

class Solution {
    public int search(int[] nums, int target) {
        if (nums == null || nums.length == 0) return -1;
        int left = 0;
        int right = nums.length;
        while (left < right) {
            int mid = left + (right - left) / 2;
            long  num = (nums[mid] < nums[0]) == (target < nums[0])
                    ? nums[mid]
                    : target < nums[0] ? Long.MIN_VALUE: Long.MAX_VALUE;
            if (num < target) left = mid + 1;
            else if (num > target) right = mid;
            else return mid;
        }
        return -1;
        
    }
}

posted on 2019-05-07 16:42  威行天下  阅读(115)  评论(0编辑  收藏  举报

导航