题意
给定一个数组 arr ,其中任意相邻的数均不相等,返回数组中任意一个局部最小值。
局部最小值定义:一个数小于左边邻居且小于右边邻居,若只有左边邻居或右边邻居,
只需要满足小于左边邻居或右边邻居即可。
思路
利用二分查找,通常二分查找应用于有序数组,这里尝试应用在无序数组中。
- 假设数组中前两个元素arr[0]、arr[1],满足arr[0] < arr[1],则可直接返回arr[0];
- 假设数组中后两个元素arr[n-1]、arr[n-2],满足arr[n-1] < arr[n-2],则可直接返回arr[n-1];
- 若不满足前两个条件,则arr[0]>arr[1],这一段单调递减;arr[n-1] > arr[n-2],,这一段单调递增;那么必然在arr[0]…arr[n-1]之间存在局部最小值点,自然想到二分查找。
令 mid = (int) (L + R) / 2,若满足:- arr[mid] < arr[mid-1] and arr[mid] < arr[mid+1],则mid 即为要找的值的索引;
- arr[mid] > arr[mid-1] and arr[mid] < arr[mid+1],则局部最小值必然在[L, mid-1]之间,继续迭代二分查找;
- arr[mid] < arr[mid-1] and arr[mid] > arr[mid+1],则局部最小值必然在[mid+1, r]之间,继续迭代二分查找;
代码
python
class BinarySearchLocalMin:
"""
arr 相邻的数不相等,查找arr中任意一个局部最小值的位置:
局部最小值定义:
arr小于左边邻居且小于右边邻居,若只有左边邻居或右边邻居,
只需要满足小于左边邻居或右边邻居即可;
"""
def solution(self, arr):
if not arr or len(arr) == 0:
return -1
n = len(arr)
if n == 1:
return 0
if arr[0] < arr[1]:
return 0
if arr[n-1] < arr[n-2]:
return n-1
l, r = 0, n - 1
# l, r 之间肯定有局部最小
while l < r - 1:
mid = int((l+r)/2)
if arr[mid] < arr[mid-1] and arr[mid] < arr[mid+1]:
return mid
else:
if arr[mid] > arr[mid - 1]:
r = mid - 1
else:
l = mid + 1
return l if arr[l] < arr[r] else r
Java
public class BinarySearchLocalMin {
// arr 相邻的数不相等!
public static int oneMinIndex(int[] arr) {
if (arr == null || arr.length == 0) {
return -1;
}
int N = arr.length;
if (N == 1) {
return 0;
}
if (arr[0] < arr[1]) {
return 0;
}
if (arr[N - 1] < arr[N - 2]) {
return N - 1;
}
int L = 0;
int R = N - 1;
// L...R 肯定有局部最小
while (L < R - 1) {
int mid = (L + R) / 2;
if (arr[mid] < arr[mid - 1] && arr[mid] < arr[mid + 1]) {
return mid;
} else {
if (arr[mid] > arr[mid - 1]) {
R = mid - 1;
} else {
L = mid + 1;
}
}
}
return arr[L] < arr[R] ? L : R;
}