【发布时间】:2012-08-27 14:57:17
【问题描述】:
给定一个整数数组,求局部最小值。如果 A[i-1] > A[i] 且 A[i]
我知道如果只有一个局部最小值,那么我们可以通过修改后的二进制搜索来解决。
但是如果已知数组中存在多个局部最小值,是否可以在O(log n)时间解决?
【问题讨论】:
标签: arrays algorithm binary-search
给定一个整数数组,求局部最小值。如果 A[i-1] > A[i] 且 A[i]
我知道如果只有一个局部最小值,那么我们可以通过修改后的二进制搜索来解决。
但是如果已知数组中存在多个局部最小值,是否可以在O(log n)时间解决?
【问题讨论】:
标签: arrays algorithm binary-search
如果不能保证数组元素是不同的,则不可能在 O(log n) 时间内做到这一点。原因如下:假设您有一个数组,其中所有 n > 1 值都相同。在这种情况下,没有一个元素可以是局部最小值,因为没有一个元素小于它的邻居。但是,为了确定所有值都相同,您必须查看所有数组元素,这需要 O(n) 时间。如果您使用的时间少于 O(n),则不一定能查看所有数组元素。
另一方面,如果保证数组元素是不同的,则可以使用以下观察在 O(log n) 时间内解决此问题:
因此,您可以构建以下递归算法:
注意这有递归关系
T(1) ≤ 1
T(2) ≤ 1
T(n) ≤ T(n / 2) + 1
使用主定理,您可以根据需要证明该算法在 O(log n) 时间内运行。
希望这会有所帮助!
还请注意,仅当数组的边小于相邻元素时,该算法才有效。
【讨论】:
局部最小值的个数可以是n/2;您无法在O(log n) 时间内将它们全部枚举出来。
【讨论】:
使用分而治之的算法。令 m = n/2,并检查值 A[m](即 是,数组中间的元素)。
案例 1:A[m−1]
案例 2:A[m + 1] > A[m]。那么数组的右半部分必须包含一个局部最小值,所以 在右半边递归。这与案例 1 对称。
案例 3:A[m − 1] > A[m] 和 A[m + 1]
【讨论】:
你的算法不适用于这个数组
15, 13, 12, 18, 19, 20, 7, 6, 5, 4, 3, 2, 1
这里的局部最小值是 12.. 但是当我检查中间元素,即 7 时,您的算法将丢弃左半部分(具有最小值)并检查右半部分。因此它不起作用
我认为只有当数组具有 A[1] ≥ A[2] 和 A[n - 1] ≤ A[n]。
【讨论】:
原题不完整。
刚刚在以下位置找到了完整的问题和详细的解释 Find local minima in an array! - 不是我的博客
给定一个唯一整数数组,其前两个数字正在减少,最后两个数字正在增加,请在数组中找到一个局部最小值。如果数组中的数字小于其左右数字,则称为局部最小值。
例如在数组 9,7,2,8,5,6,3,4 2 是一个局部最小值,因为它小于其左右数字 7 和 8。同样,5 是另一个局部最小值,因为它介于 8 和 6 之间,都大于 5。
你需要找到任何一个局部最小值。
【讨论】:
这是一个适用于 O(log n) 的解决方案。基本上,这适用于合并排序方法(分而治之)。
public class LocalMaxima {
int []a = {5,8,10,25,6,3,44,51,55,56,57,58,34,5,59};
@Test
public void localMaxima () {
System.out.println((a[localMaxima(0,a.length-1)]));
}
int localMaxima(int low, int high) {
if(high-low > 2) {
int mid = (low+high)/2;
return maxof(localMaxima(low,mid),localMaxima(mid+1, high));
}
else if(high-low == 1) {
return maxof(high,low);
}
else if(high-low == 0) {
return high;
}
if(high-low == 2) {
return maxof(maxof(low, high),low+1);
}
return 0;
}
int maxof(int i, int j) {
if(a[i] <a[j]) {
return j;
}
else {
return i;
}
}
}
【讨论】:
实际上我之前的算法可以修改为在 O(log n) 时间内获得所有最大值。我测试了它对提供的所有输入都很好。请让我知道您的反馈意见
public class LocalMaximas {
@Test
public void test () {
System.out.println("maximas: please modify code to handle if array size is <= 2");
int []a = {5,8,10,25,6,3,44,51,55,56,57,58,34,5,59,2};
localMaximas(a);
int []b = {9,7,2,8,5,6,3,4, 2}; //9,8,6,4
localMaximas(b);
int [] c= {15, 13, 12, 18, 19, 20, 7, 6, 5, 4, 3, 2, 1};//15,20
localMaximas(c);
}
public void localMaximas (int [] a) {
System.out.println("\n\n");
if(isMaxima(a,0)) {
System.out.println(a[0]);
}
if(isMaxima(a,a.length-1)) {
System.out.println(a[a.length-1]);
}
localMaximas(a,0,a.length-1);
}
int localMaximas(int []a,int low, int high) {
int mid = (low+high)/2;
if(high-low > 3) { // more than 4 items in currently divided array
if(isMaxima(a,mid)) {
System.out.println(a[mid]);
}
localMaximas(a,low, mid);
localMaximas(a,mid, high);
}
else if(high-low == 3){ //exactly 4 items in currently divided array
localMaximas(a,low, mid+1);
localMaximas(a,mid, high);
}
else if((high-low == 2) && (isMaxima(a,low+1))) {
System.out.println(a[low+1]);
}
return 0;
}
int maxof(int []a, int i, int j) {
if(a[i] <a[j]) {
return j;
}
else {
return i;
}
}
boolean isMaxima(int []a ,int mid) {
if(mid == 0) {
if(maxof(a, mid, mid+1) == mid) {
return true;
}
else {
return false;
}
}
else if(mid==a.length-1) {
if(maxof(a,mid,mid-1) == mid) {
return true;
}
else {
return false;
}
}
else {
if((maxof(a, mid, mid+1) == mid) && (maxof(a, mid, mid-1) == mid)) {
return true;
}
else {
return false;
}
}
}
}
【讨论】: