LeetCode 新題: Find Minimum in Rotated Sorted Array 解題報告-二分法模板解法
Question Solution
Suppose a sorted array is rotated at some pivot unknown to you beforehand.
(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).
Find the minimum element.
You may assume no duplicate exists in the array.
解答1:
這個題目trick的地方在於,它的旋轉pivot次數未知。所以有可能它轉了一圈又轉回了原處
所以我們代碼要處理2種情況:
我們還是用二分法來做。比起全部掃一次,二分法可以做到LogN的復雜度。
1. Sorted
這種情況簡單,先計算出mid的值,如果它處在左右的中間,證明這個數列是正常的sorted,直接返回左邊。
2. 中間斷開(也就是說旋轉過)
我們的目的是要找出存在斷口的地方。所以我們可以每次求一下mid的值,把mid 跟左邊比一下,如果是正常序,就丟掉左邊,反之丟掉右邊,不斷反復直到找到斷口。
分析一下:
比如4 5 6 7 0 1 2 從中間斷開後,它是由一個有序跟一個無序的序列組成的。
如果left = 0, right = 6,mid = 3, 那麼4, 5, 6, 7 是正序, 7, 0, 1, 2是逆序,所以我們要丟掉左邊。這樣反復操作,直到數列中只有2個數字,就是斷開處,這題我們會得到7,0,返回後一個就可以了。
以下圖示簡單描述了通過三步操作逐步逼近斷口處。每一次我們可以扔掉一半,速度是LogN.
【Leetcode】Find <wbr>Minimum <wbr>in <wbr>Rotated <wbr>Sorted <wbr>Array <wbr>解題報告
注意,丟掉半邊時,mid不可以丟掉,因為有可能mid就是答案。
例子: 3, 1, 2 的時候,3, 1是逆序,1, 2是正序,如果你扔掉1,2你就丟掉了答案。
1 // Solution 1:
2 public int findMin1(int[] num) {
3 if (num == null || num.length == 0) {
4 return 0;
5 }
6
7 if (num.length == 1) {
8 return num[0];
9 }
10
11
12 // 至少有2個元素,才有討論的價值
13 int l = 0;
14 int r = num.length - 1;
15
16 while (l < r) {
17 int mid = l + (r - l)/2;
18 // Means that there is no rotate.
19 if (num[mid] >= num[l] && num[mid] <= num[r]) {
20 return num[0];
21 }
22
23 // rotate > 0的情況
24 if (l == r - 1) {
25 // 當只余下2個元素的時候,這裡是斷點,右邊的是小值
26 return num[r];
27 }
28
29 if (num[mid] >= num[l]) {
30 // The left side is sorted. Discard left.
31 l = mid;
32 } else {
33 // The right side is sorted.
34 r = mid;
35 }
36 }
37
38 return 0;
39 }
復制代碼
解答2:
采用九章算法的二分法模板來解:
這個模板最大的好處是 while(left < right - 1) 這樣的話,終止時就一定是left = right - 1,而且mid 一直會是在中間,不會靠到left去。判斷起來會相當
便利。
復制代碼
1 // solution 2:
2 public int findMin(int[] A) {
3 if (A == null || A.length == 0) {
4 return 0;
5 }
6
7 if (A.length == 1) {
8 return A[0];
9 } else if (A.length == 2) {
10 return Math.min(A[0], A[1]);
11 }
12
13 // 至少有3個元素,才有討論的價值
14 int l = 0;
15 int r = A.length - 1;
16
17 while (l < r - 1) {
18 int m = l + (r - l) / 2;
19
20 // means that there is no rotate.
21 if (A[m] < A[r] && A[m] > A[l]) {
22 return A[0];
23 }
24
25 // left side is sorted.
26 if (A[m] > A[l]) {
27 l = m;
28 } else {
29 r = m;
30 }
31 }
32
33 return A[r];
34 }
復制代碼
所以以後一定要多使用模板化的編程 ,特別是這裡總結的二分法模板:
復制代碼
1 while (l < r - 1) {
2 int m = l + (r - l) / 2;
3
4 // means that there is no rotate.
5 ... 這裡添加各種退出條件,比如找到了目標值等 8
9 // left side is sorted.
10 if (A[m] > A[l]) {
11 l = m;
12 } else {
13 r = m;
14 }
15 }