找到给定数组的1D峰值

时间:2014-02-14 20:01:33

标签: java arrays algorithm

我正在为一维数组编写峰值查找算法的代码。我已阅读此帖Peak finding algorithm。这正是我想要做的,有关于时间复杂性的讨论,但没有任何类型的伪代码。问题:

  

给定一个数组[a,b,c,d,e,f,g],其中ag是数字,b是一个峰值,当且仅当a<=bb>=c时。

示例:给定数组{1,2,3,4,5,19,25,20},应返回索引6边缘情况应该给出:

{100,4,3,1,19,20} -- index 0

{1,3,5,19,20} -- index 4

我已在Java中实施。我当前的运行时间是O(n)。我想知道这是否可以改善

public static int naive(int[] arr){
        int l=arr.length;
        if (arr[0]>=arr[1]) {
            return 0;
        }
        if (arr[l-1]>arr[l-2]){
            return l-1;
        }
        for (int i=1; i < arr.length-1;i++){
             if (arr[i] >= arr[i-1] && arr[i] >= arr[i+1] ){
                 return i;
             }
        }
        return -1;
    }

4 个答案:

答案 0 :(得分:2)

以下功能可能比您的更有效。请注意,这会找到 本地最大值

    public static int findLocalMaximum(int[] arr){
        int i = 0;
        while(i + 1 < arr.length && arr[i+1] >= arr[i]) {
            ++i;
        }
        return i;
    }

编辑:以下函数查找问题中定义的峰值。请注意,我在while循环中删除了边界检查,因为仅在arr[l-2] > arr[l-1]时才会到达循环,因此while循环中的条件将为false并且将返回l-2

    public static int findPeak(int[] arr){
        int l = arr.length;
        if(arr[0] >= arr[1]) {
            return 0;
        }

        if(arr[l-1] >= arr[l-2]) {
            return l-1;
        }

        int i = 1;
        while(arr[i+1] > arr[i]) {
            ++i;
        }
        return i;
    }

答案 1 :(得分:2)

如果我可以提出我的解决方案:

public static int findPeak(int[] array, int start, int end) {
    int index = start + (end - start) / 2;

    if (index - 1 >= 0 && array[index] < array[index - 1]) {
        return findPeak(array, start, index - 1);
    } else if (index + 1 <= array.length - 1 && array[index] < array[index + 1]) {
        return findPeak(array, index + 1, end);
    } else {
        return array[index];
    }
}

我认为在if语句中直接处理边缘情况更简单。我还测试了几个输入,它似乎工作。

答案 2 :(得分:0)

binary search-like algorithm应该有效。采用divide and conquer策略。由于您对single peak感兴趣,因此您可以做的最好的事情是O(log n)。但是如果你想找到所有的峰值,它至少会是O(n)

以下是divide-and conquer algorithm

public static int peak1D(int[] arr, int start, int end){
          //edge cases
        if (end-start==1){
            if (start==0)
                return start;
            else 
             return end;
        }
        int i = start+end>>>1;
        if (arr[i]<arr[i-1])
           return peak1D(arr,start,i);
        if (arr[i]<arr[i+1]){
            return peak1D(arr, i, end);
        }
        else
            return i;
    }

我测试了几个输入,它似乎工作。我处理边缘情况并不是很好。虽然这是简单的推理

答案 3 :(得分:0)

假设Array是全局的,为了简单起见,你可以根据需要传递它。

    private static int getPeak1D(int start,int end)
{
    int x = (start+end)/2;

    if(     (x == 0 && array[x] >= array[x+1]) ||
            (x == array.length-1 && array[x]>=array[x-1]) ||
            (x>0 && x< array.length-1 && array[x] >= array[x-1] && array[x] >= array[x+1]))
        return x;

    if(x+1 < array.length && array[x] < array[x+1])
        temp =  getPeak1D(x+1,end);

    if(temp > -1)
        return temp;

    if(x-1 > -1 && array[x] < array[x-1])
        return getPeak1D(0,x-1);
    else
        return -1;
}

首先检查峰的第一个边,第二个边和内部。 如果没有找到峰值,如果array [x + 1]&gt; array [x],Second if将转到数组的右半部分。我们将它存储在temp(我将它作为全局)我们不返回它,因为如果数组[x + 1]和数组[x-1]都比数组[x]大,但右侧没有找到任何如果检查左侧,你应该去第三个

检查此背后的逻辑 https://courses.csail.mit.edu/6.006/spring11/rec/rec02.pdf