leetcode-搜索旋转排序数组

404 阅读3分钟

这是我参与8月更文挑战的第22天,活动详情查看:8月更文挑战

这周末回了一趟老家,挺近的,开车1小时。来回都在嘀嗒出行接了顺风车的单子,比较奇怪的是,在嘀嗒出行和哈啰出行比在滴滴找到了更多比较顺路的乘客,可能是滴滴顺风车对乘客端价格较高,导致乘客更原因在其他平台发单子。

我作为司机,主要考虑的是顺路,因为顺风车的价格相对较低,如果绕路就非常不划算,引出了一个思考,系统是怎么计算顺路匹配度的呢?

最简单的方式,导航计算出司机的原路线和接单后的新路线,然后直接计算出2条路线的差值,除以原路线的里程,就可以认为是不匹配度,然后顺路匹配度 = 1-不匹配度。

不过这样的方式有1个明显的缺点,极度理性,因为对司机来说,至少对我来说,跟我当前主要方向完全反方向的3km和垂直方向的3km,体感是不一样的,反方向的3km会让我觉得我绕的比较远,而垂直方向的,会让我觉得绕的不多。所以可能还需要考虑的1个维度是方向的向量夹角,来对这段里程进行加权,当然如果能考虑到预计出行时间段这段路程的路况就更好了。

以上是因为本周末回来家2次顺风车经历,对顺路匹配计算的随想,还是回到leetcode,今天继续做第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:
输入: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次旋转,所以数组是2个分别有序数据的拼接,但是拼接点未知,那怎么办呢?
其实还是可以使用二分查找,二分查找的前提并不是数组完全有序,而是二分后,有办法能快速判断可能出现在哪个1半里面。虽然本题不是完全有序,但是其实还是可以判断的,因为可以发现的是,数组二分后,一定有一半是有序的,这个非常重要,既然有一半是有序的,那我们可以通过这一半的头和尾判断target是否在这一半里面,如果在,那就继续查找这一半,如果不在,那就是在另外一半,然后递归下去查找即可。
下图是二分后,一定有一半是完全有序的示意图,蓝框就是有序的一半:

33.jpg

Java版本代码

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