Java 在一维数组/直方图中查找局部最小值/最大值
我试图找到数组中所有局部极小值和极大值的指数 例如:Java 在一维数组/直方图中查找局部最小值/最大值,java,algorithm,Java,Algorithm,我试图找到数组中所有局部极小值和极大值的指数 例如: int[] array = {5,4,3,3,3,3,3,2,2,2, 6,6,8,5,5,5,3,3,2,1, 1,4,4,7}; // | | | // Indices: 0,1,2,3,4,5,6,7,8,9, 10,1,2,3,4,5,6,7,8,9, 20,1,2,3 // Minima: 8, 20 // Maxima
int[] array = {5,4,3,3,3,3,3,2,2,2, 6,6,8,5,5,5,3,3,2,1, 1,4,4,7};
// | | |
// Indices: 0,1,2,3,4,5,6,7,8,9, 10,1,2,3,4,5,6,7,8,9, 20,1,2,3
// Minima: 8, 20
// Maxima: 12
我提出了一个算法,对此我有几个问题:
- 有更好的吗?:)李>
- 我用枚举的方法来实现这种二元论,即向上和向上都是“向上”。我觉得很乱。有什么建议吗
- 你有更好的方法名吗?direction()(+返回值)某种程度上意味着stright不是dir。但同时它也是,因为它是欧洲货币联盟的一个组成部分。嗯
- 它适用于给定的数组。你有没有看到一种情况,它没有
import java.util.ArrayList;
公共类MinMaxFinder{
私有int[]数组;
私有数组列表极小值;
私人ArrayList maxima;
私有枚举方向{
上,下,直上,直下,直;
公共方向(){
if(this==向上| | this==直线向上){
返回;
}else if(this==向下| | this==直线向下){
返回下来;
}否则{
直线返回;
}
}
公共布尔值isStraight(){
如果(this==直线向下| | this==直线向上| | this==直线){
返回true;
}否则{
返回false;
}
}
公共布尔值hasDifferentDirection(方向其他){
如果(this!=直线和其他!=直线和此.direction()!=其他.direction()){
返回true;
}
返回false;
}
}
公共MinMaxFinder(int[]数组){
this.array=数组;
}
公共无效更新(){
极小值=新数组列表();
maxima=新的ArrayList();
方向分段DIR=方向向下;
int indexOfDirectionChange=0;
int-prevVal=数组[0];
int arrayLength=array.length;
对于(inti=1;i考虑一组第一个差异d[i]=a[i]-a[i-1]
如果d[i]
为正,则a
在上一步中增加,如果d[i]
为负值,然后a
减小。因此,d
的符号从正变为负表示a
的局部最大值正在增大,现在正在减小。类似地,从负变为正表示局部最小值。类似的“应该”工作,概念上可能不太复杂。
扫描阵列一次,并注册mins和maxs
值得一提的事情:
1) if(direction<0){}else{}可能可以删除,但我没有时间考虑细节。
2) 关键思想是,根据第一个“方向”(无论我们首先看到的是最小值还是最大值),for循环顺序会发生变化。
3) 如果有多个项目,它将始终保留最后一个元素(最高索引)
if(a.长度<2){
返回;
}
List mins=new ArrayList();
List maxs=new ArrayList();
int i=1;
int prev=0;
int方向=0;
对于(intj=1,k=0;j我想我明白了。谢谢大家!你们的想法帮了我很大的忙
以下解决方案适合我:
ArrayList<Integer> mins = new ArrayList<Integer>();
ArrayList<Integer> maxs = new ArrayList<Integer>();
int prevDiff = array[0] - array[1];
int i=1;
while(i<array.length-1){
int currDiff = 0;
int zeroCount = 0;
while(currDiff == 0 && i<array.length-1){
zeroCount++;
i++;
currDiff = array[i-1] - array[i];
}
int signCurrDiff = Integer.signum(currDiff);
int signPrevDiff = Integer.signum(prevDiff);
if( signPrevDiff != signCurrDiff && signCurrDiff != 0){ //signSubDiff==0, the case when prev while ended bcoz of last elem
int index = i-1-(zeroCount)/2;
if(signPrevDiff == 1){
mins.add( index );
}else{
maxs.add( index );
}
}
prevDiff = currDiff;
}
ArrayList mins=new ArrayList();
ArrayList maxs=新的ArrayList();
int-prevDiff=数组[0]-数组[1];
int i=1;
虽然(iWhy)索引0(数字5)不是局部最大值?与索引23相同。第一个/最后一个数字永远不会是最大值/最小值吗?在重复值的情况下,您选择的索引中的哪一个?例如:a={5,6,6},“max”必须是2,或者它可以是1,2或3??同样,我同意@DaDaDom:7(索引23)应为maximumI think index=2(中间6)最接近“真实/模拟”最小值。这仅给出与其直接邻域相关的局部最小值/最大值。此外,还必须迭代两个数组。您的问题是局部最小值/最大值。如何定义局部最小值/最大值?注意,我为您草拟了一个想法。不必实际存储第一个差分数组,您只需计算它们当您遍历输入数组并跟踪符号的变化时。是的,我很感激您的建议!:)问题是这些值是离散的。1222221->索引3处的最大值。虽然两个相邻值都是2(在差异数组中,它将是0)。这就是为什么我对直线上升和直线下降进行区分。d[i]=a[i]-a[i-1]是Direction currentDir=currValprevVal?Direction.UP:Direction.diright);因此,问题是您想要一个相等值范围的中间索引?请在d[i]处记录索引
更改符号,然后计算数字n
,其中后续的d
为零。您需要索引i+n/2
。对。我也必须查看零右侧的符号。因为它可能类似于{1,2,2,2,3,3,2,2,2}
所以有从1to2到2to3的变化,但两者都在上升。所以这两个序列不再有趣了。但是你让我走上了一条好的道路:)我用嵌套循环来尝试。谢谢!这很好。虽然第3点对我很重要。是的,我没有阅读我对你的问题的评论的后续内容。但是它是使用这种方法,计算“中值”指数相当容易。如果你对你的答案感到满意,那么你应该接受你的答案!
if(a.length < 2){
return;
}
List<Integer> mins = new ArrayList<Integer>();
List<Integer> maxs = new ArrayList<Integer>();
int i=1;
int prev = 0;
int direction = 0;
for(int j=1, k = 0;j<a.length && (direction = a[j]-a[k]) == 0;j++, k++);
if(direction == 0){
//Array contains only same value.
return;
}
if(direction < 0){
while(i<a.length){
for(;i<a.length && a[prev] >= a[i];i++,prev++);
mins.add(prev);
for(;i<a.length && a[prev] <= a[i];i++,prev++);
maxs.add(prev);
i++;prev++;
}
}
else{
while(i<a.length){
for(;i<a.length && a[prev] <= a[i];i++,prev++);
maxs.add(prev);
for(;i<a.length && a[prev] >= a[i];i++,prev++);
mins.add(prev);
i++;prev++;
}
}
//maxs and mins now contain what requested
ArrayList<Integer> mins = new ArrayList<Integer>();
ArrayList<Integer> maxs = new ArrayList<Integer>();
int prevDiff = array[0] - array[1];
int i=1;
while(i<array.length-1){
int currDiff = 0;
int zeroCount = 0;
while(currDiff == 0 && i<array.length-1){
zeroCount++;
i++;
currDiff = array[i-1] - array[i];
}
int signCurrDiff = Integer.signum(currDiff);
int signPrevDiff = Integer.signum(prevDiff);
if( signPrevDiff != signCurrDiff && signCurrDiff != 0){ //signSubDiff==0, the case when prev while ended bcoz of last elem
int index = i-1-(zeroCount)/2;
if(signPrevDiff == 1){
mins.add( index );
}else{
maxs.add( index );
}
}
prevDiff = currDiff;
}