1. 程式人生 > 其它 >LeetCode HOT 100:搜尋旋轉排序陣列

LeetCode HOT 100:搜尋旋轉排序陣列

題目:33. 搜尋旋轉排序陣列

題目描述:

一個整數陣列,陣列每個值都不相同,且該整數陣列是一個被旋轉過的陣列。被旋轉過的陣列是指,由一個遞增的陣列,從某一個下標開始往後的元素,移到最開頭。舉個例子:陣列[1, 3, 4, 5,7],假設從下標為2處開始旋轉,得到旋轉過的陣列為[4, 5, 7, 1, 3],如果從下標0處開始旋轉,那麼相當於沒有旋轉,還是原陣列。
本題能保證,給你的整數陣列,一定是每個值都不相同,且一定是一個旋轉過的陣列。然後給你一個target的值,讓你返回target值在陣列中的下標,如果target不在陣列中,返回-1。要求時間複雜度為O(logn)

步驟:

這題一看要求時間複雜度O(logn)

,想到使用二分法,但是二分法需要陣列滿足遞增,這一題不滿足。但是還是可以使用二分法,只不過思路稍微轉變一下。
1、下標l0rn - 1,開始進行二分。取得兩者中間下標mid,如果mid下標的值正好等於target,直接返回結果即可。
2、如果[l, mid]是有序陣列,且 target值在[l, mid]範圍上,則我們應該將搜尋範圍縮小至 [l, mid - 1],否則在[mid + 1, r]範圍中尋找。
3、如果[mid, r]是有序陣列,且 target值在[mid, r]範圍上,則我們應該將搜尋範圍縮小至 [mid + 1, r],否則在[l, mid - 1]範圍中尋找。

解釋:

1、為什麼本題可以使用二分法?二分法一般都需要陣列有序。這個陣列因為被旋轉過,看似是無序的,其實是區域性有序的。例如[4, 5, 7, 1, 3][4, 5, 7][1, 3]都是有序的,所以在某些有序範圍內,可以進行二分。
2、為什麼要判斷[l, mid][mid, r]是否有序?因為只有有序了,才能進行範圍縮小。而至於在有序範圍中怎麼縮小,上面的步驟23說得很清晰了。

程式碼:

	int N = nums.length;
        if (N == 0) return -1;
        if (N == 1) return nums[0] == target ? 0 : -1;

        int L = 0, R = N - 1;
        int M = 0;

        while (L <= R) {
            M = L + ((R - L) >> 1);
            if (nums[M] == target) return M;

            // [L, M]有序,說明[L, R]無序
            if (nums[L] <= nums[M]) {
                // target在[L, M]範圍上,接下來左側繼續二分
                if (target >= nums[L] && target < nums[M]) {
                    R = M - 1;
                } else { // 去右側二分
                    L = M + 1;
                }
            } else { // [L, M]無序,說明[M, R]有序
                if (target > nums[M] && target <= nums[R]) { // 如果[M, R]範圍上包括了target,去右側二分
                    L = M + 1;
                } else { // 去左側二分
                    R = M - 1;
                }
            }
        }

        return -1;