【算法】【线性表】搜索旋转排序数组(无重复数据)

发布时间 2023-12-08 10:26:38作者: 酷酷-

1  题目

给定一个有序数组,但是数组以某个元素作为支点进行了旋转(比如,0 1 2 4 5 6 7 可能成为4 5 6 7 0 1 2)。给定一个目标值target进行搜索,如果在数组中找到目标值返回数组中的索引位置,否则返回-1。你可以假设数组中不存在重复的元素。

样例 1:

输入:

数组 = [4, 5, 1, 2, 3]
target = 1

输出:

2

解释:1在数组中对应索引位置为2。

样例 2:

输入:

数组 = [4, 5, 1, 2, 3]
target = 0

输出:

-1

解释:0不在数组中,返回-1。

2  解答

public class Solution {
    /**
     * @param a: an integer rotated sorted array
     * @param target: an integer to be searched
     * @return: an integer
     */
    public int search(int[] a, int target) {
    
        // write your code here
        // 1、如果数组为空或者长度为0 返回-1
        if (a == null || a.length == 0) {
            return -1;
        }
        // 定义两个左右指针
        int left = 0;
        int right = a.length - 1;
        while (left <= right) {
            // 计算中间位置
            int middle = (left + right) / 2;
            // 如果相等那么直接返回
            if (a[middle] == target) {
                return middle;
            }
            // 因为不是绝对的顺序,所以这里看下是往左边继续二分查找还是右边
            // 怎么判断 先不管target情况,看middle 和 left或者right
            // middle >= left 说明左边是升序的 否则右边是升序的
            if (a[middle] >= a[left]) {
                // 左边升序的情况下,target在顺序内就在左边找,否则就去右边找
                if (a[left] <= target && target < a[middle]) {
                    right = middle - 1;
                } else {
                    left = middle + 1; 
                }
            } else {
         // 右边顺序的情况下,target在顺序内就在右边找,否则就去左边找
if (a[middle] <= target && target <= a[right]) { left = middle + 1; } else { right = middle - 1; } } } return -1; } }

3  问题

3.1  middle 的计算

关于 middle 的计算:有的人会写:left + (right - left) / 2 有的人会写:(left + right) / 2,其实两者是相等的哈。

但是考虑边界的话:在left和right都很大的时候会出现溢出的情况,从而导致数组访问溢出。

所以优先采用:left + (right-left) / 2 或者是使用神奇的位运算:   mid=left+((right-left)>>>1),右移一位表示除2

3.2  理解旋转以及旋转的影响

旋转怎么理解呢?我小画一下:

旋转了解后,那么旋转对我们的查询有什么影响呢?数组有序的话,二分查找是非常高效的,只需要每次定位到中间位置然后继续左边或者右边继续递归查找即可。那么旋转以后对我们的二分查找的影响是哪里呢?

3.3  代码中的问题

这里第一次写的时候,自己把自己绕进去了,唉,判断要充分。