我正在尝试查找数组中所有局部最小值和最大值的索引。
示例:
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
我提出了一个算法,我几乎没有问题:
-
import java.util.ArrayList;
public class MinMaxFinder {
private int[] array;
private ArrayList<Integer> minima;
private ArrayList<Integer> maxima;
private enum Direction{
UP, DOWN, STRAIGHT_UP, STRAIGHT_DOWN, STRAIGHT;
public Direction direction(){
if(this==UP || this==STRAIGHT_UP){
return UP;
}else if(this==DOWN || this==STRAIGHT_DOWN){
return DOWN;
}else{
return STRAIGHT;
}
}
public boolean isStraight(){
if(this==STRAIGHT_DOWN || this==STRAIGHT_UP || this==STRAIGHT){
return true;
}else{
return false;
}
}
public boolean hasDifferentDirection(Direction other){
if(this!=STRAIGHT && other!=STRAIGHT && this.direction() != other.direction() ){
return true;
}
return false;
}
}
public MinMaxFinder(int[] array){
this.array = array;
}
public void update() {
minima = new ArrayList<Integer>();
maxima = new ArrayList<Integer>();
Direction segmentDir = Direction.DOWN;
int indexOfDirectionChange = 0;
int prevVal = array[0];
int arrayLength = array.length;
for(int i=1; i<arrayLength; i++){
int currVal = array[i];
Direction currentDir = currVal<prevVal?Direction.DOWN:(currVal>prevVal?Direction.UP:Direction.STRAIGHT);
prevVal = currVal;
if(currentDir.hasDifferentDirection(segmentDir)){
int changePos = (indexOfDirectionChange+i-1)/2;
if(currentDir.direction() == Direction.DOWN){
maxima.add(changePos);
}else{
minima.add(changePos);
}
segmentDir = currentDir;
indexOfDirectionChange = i;
}else if( currentDir.isStraight() ^ segmentDir.isStraight() ){
indexOfDirectionChange = i;
if(currentDir.isStraight() && segmentDir.direction()==Direction.UP){
segmentDir=Direction.STRAIGHT_UP;
}else if(currentDir.isStraight() && segmentDir.direction()==Direction.DOWN){
segmentDir=Direction.STRAIGHT_DOWN;
}else{
segmentDir = currentDir;
}
}
}
}
public ArrayList<Integer> getMinima() {
return minima;
}
public ArrayList<Integer> getMaxima() {
return maxima;
}
}
答案 0 :(得分:1)
考虑一系列第一个差异d[i] = a[i] - a[i-1]
。
如果d[i]
为正,则a
在最后一步增加,如果d[i]
为负,则a
减少。因此,d
从正数到负数的符号变化表明a
正在增加,现在正在减少,是一个局部最大值。同样,阴性到阳性表示当地最小值。
答案 1 :(得分:0)
像这样的“应该”工作,它可能在概念上不那么复杂。 扫描数组一次并记录分钟和最大值。
值得一提的是:
1)if(方向&lt; 0){} else {}可能会被删除,但我没有时间考虑细节。
2)关键的想法是,取决于第一个“方向”(无论我们看到最小值还是最大值),for循环顺序变化。
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
答案 2 :(得分:0)
我想我明白了。多谢你们!你的想法给了我很多帮助!
以下解决方案适用于我:
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;
}