1. 程式人生 > >Rotated Sorted Array(旋轉陣列總結)

Rotated Sorted Array(旋轉陣列總結)

首先什麼叫旋轉陣列,把一個數組最開始的若干個元素搬到陣列的末尾,我們稱之為陣列的旋轉。例如陣列{3,4,5,1,2}為{1,2,3,4,5}的一個旋轉。對於這樣的陣列,我們可以畫一下的一個圖來表示。


對於 Rotated Sorted Array 來說,主要有兩類問題:

  1. 尋找Rotated Sorted Array的最小值。
  2. 在Rotated Sorted Array裡面查詢給定的數。
對於第一類問題又分為以下兩種問題:
  • 陣列中沒有重複元素,找最小值
  • 陣列中有重複元素,找最小值
對於第二類問題,又分為以下兩種問題:
  • 陣列中沒有重複元素,找給定的值
  • 陣列中有重複元素, 找給定的值
下面看: 第一類問題
,找Rotated Sorted Array中最小值,對於已經排好序的陣列來說,查詢問題我們首先應該想到的是二分查詢。 那麼在陣列中沒有重複元素時候查詢的程式碼為(重點需要注意的是,需要先從end開始比較):
// 在沒有重複元素時候,查詢Rotated Sorted Array中的最小值
public int findMin(int[] nums) {
    if (nums == null || nums.length == 0) {
        return -1;
    }
    int start = 0;
    int end = nums.length - 1;
    int mid;
    while (start + 1 < end) {
        mid = start + ((end - start) >> 1);
        //為了防止rotated array 蛻化成這種
        //1 2 3 4 5 6
        //需要先和end 比較
        if (nums[mid] <= nums[end]) {
            end = mid;
        } else {
            start = mid;
        }
    }
    if (nums[start] < nums[end]) {
        return nums[start];
    }
    return nums[end];
}
陣列中有重複元素時查詢最小值的程式碼為:
// Rotated Sorted Array有重複元素時查詢最小值
public int findMin(int[] nums) {
    if (nums == null || nums.length == 0) {
        return -1;
    }
    int start = 0;
    int end = nums.length - 1;
    int mid;
    while (start + 1 < end) {
        mid = start + ((end -start) >> 1);
        if (nums[mid] < nums[end]) {
            end = mid;
        } else if (nums[mid] > nums[end]) {
            start = mid;
        } else {
            //如果相等則 end 往前一步
            --end;
        }
    }
    if (nums[start] < nums[end]) {
        return nums[start];
    }
    return nums[end];
} 
第二類問題,在Rotated Sorted Array中查詢給定的元素: 陣列中沒有重複元素時,程式碼為:
// 陣列中沒有重複元素時,查詢給定的元素
public int search(int[] nums, int target) {
        if (nums == null || nums.length == 0) {
            return -1;
        }
        int start = 0;
        int end = nums.length - 1;
        int mid;
        while (start + 1 < end) {
            mid = start + ((end - start) >> 1);
            if (nums[mid] == target) {
                return mid;
            } else if (nums[mid] > nums[start]) {
               // 屬於 上圖中第二象限的區段
                if (target >= nums[start] && target <= nums[mid]) {
                    end = mid;
                } else {
                    start = mid;
                }
            } else {
                //屬於上圖中第四象限的區段
                if (target >= nums[mid] && target <= nums[end]) {
                    start = mid;
                } else {
                    end = mid;
                }
            }
        }
        if (nums[start] == target) {
            return start;
        } 
        if (nums[end] == target) {
            return end;
        }
        return -1;
    }
陣列中有重複元素時,查詢給定的元素:
// 旋轉陣列中有重複時查詢給定元素
public int search(int[] nums, int target) {
    if (nums == null || nums.length == 0) {
        return -1;
    }
    int start = 0;
    int end = nums.length - 1;
    int mid;
    // 先從end開始比較
    while (start + 1 < end) {
        mid = start + ((end - start) >> 1);
        if (nums[mid] == target) {
            return mid;
        } else if (nums[mid] > nums[end]) { // 在上圖中第二象限的線段上
            if (target >= nums[start] && target <= nums[mid]) {
                end = mid;
            } else {
                start = mid;
            }
        } else if (nums[mid] < nums[end]) {  //在上圖中第四象限的線段上
            if (target >= nums[mid] && target <= nums[end]) {
                start = mid;
            } else {
                end = mid;
            }
        } else {
            --end;  //end向前跨一步
        }
    }
    if (nums[start] == target) {
        return start;
    } 
    if (nums[end] == target) {
        return end;
    }
    return -1;
}


-------------EOF------------