33. 搜索旋轉排序數組

題目:

假設按照升序排序的數組在預先未知的某個點上進行了旋轉。

( 例如,數組 [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

這道題其實是要我們明確「二分」的本質是什么。
「二分」不是單純指從有序數組中快速找某個數,這只是「二分」的一個應用。
「二分」的本質是兩段性,并非單調性。只要一段滿足某個性質,另外一段不滿足某個性質,就可以用「二分」。


兩段有序值的分布

思路:

二分法:
如上所示我畫了個圖,其實每次我們在判斷中值的時候都會拿到兩個分別是有序的片段,且左端的值是比右端的大的
我們要先根據 nums[mid] 與 nums[l] 的關系判斷 mid 是在左段還是右段,接下來再判斷 target 是在 mid 的左邊還是右邊,從而來調整左右邊界 l 和 r。這樣就做到了我們每次其實都是在一側有序片段上進行比較

class Solution {
    public int search(int[] nums, int target) {
        int l=0,r=nums.length-1,mid=0;
        while (l<=r){
            mid=l+(r-l)/2;
            if(nums[mid]==target){
                return mid;
            }
            //根據mid和l的關系判斷,mid在左邊還是右邊
            //由于左段是恒大于右端的,所以只要mid大于l初,mid必然在左段上
            if (nums[mid]>=nums[l]){
                //中值大于左側的值,目前mid處于左段,mid左側是升序
                //(這里不用寫target<=nums[mid],寫target<nums[mid]就行,因為前面已經比較過,去除這個case了)
                if (target>=nums[l]&&target<nums[mid]){
                    r=mid-1;
                }else {
                    l=mid+1;
                }
            }else {
                //中值小于左邊的值,目前mid處于右端,右側是升序
                if (target<=nums[r]&&target>nums[mid]){
                    l=mid+1;
                }else {
                    r=mid-1;
                }

            }
        }
        return mid;
    }
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容