LeetCode 新题: Find Minimum in Rotated Sorted Array 解题报告-二分法模板解法
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.
SOLUTION 1:
这个题目trick的地方在于,它的旋转pivot次数未知。所以有可能它转了一圈又转回了原处
所以我们代码要处理2种情况:
我们还是用二分法来做。比起全部扫一次,二分法可以做到LogN的复杂度。
1. Sorted
这种情况简单,先计算出mid的值,如果它处在左右的中间,证明这个数列是正常的sorted,直接返回左边。
我们的目的是要找出存在断口的地方。所以我们可以每次求一下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.
注意,丢掉半边时,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 }
SOLUTION 2:
采用九章算法的二分法模板来解:// bug 1: should not use l = m + 1 and r = m - 1.
// this may discard the minumul value.
A example: 3, 1, 2.
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 }
SOLUTION 3:
在解答2的基础之上,可以把判断是否rotated的statement去掉,然后每次丢弃有序数列时,先丢弃右边的。这样子即使是从未rotated的也没有关系,因为一直是丢右边的
直到余下左边最后2个。
1 public int findMin(int[] num) { 2 if (num == null || num.length == 0) { 3 return 0; 4 } 5 6 int l = 0; 7 int r = num.length - 1; 8 9 while (l < r - 1) { 10 int m = l + (r - l) / 2; 11 12 if (num[m] < num[r]) { 13 // bug 1: should not use l = m + 1 and r = m - 1. 14 // this may discard the minumul value. 15 r = m; 16 } else { 17 l = m; 18 } 19 } 20 21 return Math.min(num[l], num[r]); 22 }
SOLUTION 4:
在解答3的基础之上先,预判断是不是旋转过,这样如果没有旋转我们可以直接把解算出即可。
1 public int findMin(int[] num) { 2 if (num == null || num.length == 0) { 3 return 0; 4 } 5 6 int l = 0; 7 int r = num.length - 1; 8 9 if (num[l] < num[r]) { 10 return num[l]; 11 } 12 13 while (l < r - 1) { 14 int m = l + (r - l) / 2; 15 16 if (num[m] < num[r]) { 17 // bug 1: should not use l = m + 1 and r = m - 1. 18 // this may discard the minumul value. 19 r = m; 20 } else { 21 l = m; 22 } 23 } 24 25 return Math.min(num[l], num[r]); 26 }
FOLLOW UP:
LeetCode 新题: Find Minimum in Rotated Sorted Array II 解题报告-二分法模板解法
GitHub:
GitHub代码链接posted on 2014-10-24 18:37 Yu's Garden 阅读(2558) 评论(0) 编辑 收藏 举报