Поиск максимального значения в массиве с помощью рекурсии

на один из вопросов, меня попросили решить, я нашел максимальное значение массива с помощью цикла for, так что я пытался найти его с помощью рекурсии и вот что я придумал:

public static int findMax(int[] a, int head, int last) {

    int max = 0;
    if (head == last) {
        return a[head];
    } else if (a[head] < a[last]) {
        return findMax(a, head + 1, last);
    } else {
        return a[head];
    }
}

таким образом, он отлично работает и получает максимальное значение, но мой вопрос : Нормально ли иметь для базового случая возврат[head] и для случая, когда значение в голове > значение наконец?

11 ответов


вы можете так же легко сделать это только с одним счетчиком, просто индекс значения, которое вы хотите сравнить на этот раз:

public static int findMax(int[] a, int index) {
    if (index > 0) {
        return Math.max(a[index], findMax(a, index-1))
    } else {
        return a[0];
    }
}

Это намного лучше показывает, что происходит, и использует макет "рекурсии" по умолчанию, например, с общим базовым шагом. Первоначальный вызов-это выполнение findMax(a, a.length-1).


на самом деле все гораздо проще. Базовый случай, если вы достигли конца массива ("else" часть троичного блока управления ниже). В противном случае вы возвращаете максимум текущего и рекурсивного вызова.

public static int findMax(int[] a) {
    return findMax(a, 0);
}
private static int findMax(int[] a, int i) {
    return i < a.length
           ? Math.max(a[i], findMax(a, i + 1))
           : Integer.MIN_VALUE;
}

в каждом элементе вы возвращаете больший из текущего элемента и все элементы с большим индексом. Integer.MIN_VALUE будет возвращен только для пустых массивов. Это работает в линейном времени.


Я бы решил это, разделив массив на половину при каждом рекурсивном вызове.

 findMax(int[] data, int a, int b)

где A и B-индексы массива.

условие остановки-когда b - a <= 1, тогда они соседи, а max-max (a, b);

первоначальный вызов:

 findMax(int[] data, int 0, data.length -1);

это уменьшает максимальную глубину рекурсии от N до log2 (N).
Но поисковое усилие все еще остается O(N).

в результате

int findMax(int[] data, int a, int b) {
   if (b - a <= 1) {
     return Math.max(data[a], data[b]);
   } else {
     int mid = (a+b) /2; // this can overflow for values near Integer.Max: can be solved by a + (b-a) / 2; 
     int leftMax =  findMax(a, mid);
     int rightMax = findMax(mid +1, b);
     return Math.max(leftMax, rightMax);
   }
}

Как насчет этого ?

public static int maxElement(int[] a, int index, int max) {
    int largest = max;
    while (index < a.length-1) {
        //If current is the first element then override largest
        if (index == 0) {
            largest = a[0];
        }
        if (largest < a[index+1]) {
            largest = a[index+1];
            System.out.println("New Largest : " + largest); //Just to track the change in largest value
        }
        maxElement(a,index+1,largest);
    }
    return largest;
}

я наткнулся на эту тему, и это мне очень помогло. Прилагается мой полный код как в рекурсии, так и в случаях divide&conquer. Время выполнения для divide&conquer немного лучше, чем рекурсия.

//use divide and conquer.
public int findMaxDivideConquer(int[] arr){
    return findMaxDivideConquerHelper(arr, 0, arr.length-1);
}
private int findMaxDivideConquerHelper(int[] arr, int start, int end){
    //base case
    if(end - start  <=  1) return Math.max(arr[start], arr[end]);
    //divide
    int mid = start + ( end - start )/2;
    int leftMax =findMaxDivideConquerHelper(arr, start, mid);
    int rightMax =findMaxDivideConquerHelper(arr, mid+1, end);
    //conquer
    return Math.max( leftMax, rightMax );
}

// use recursion. return the max of the current and recursive call
public int findMaxRec(int[] arr){
    return findMaxRec(arr, 0);
}
private int findMaxRec(int[] arr, int i){
    if (i == arr.length) {
        return Integer.MIN_VALUE;
    }
    return Math.max(arr[i], findMaxRec(arr, i+1));
}

class Test
{
    int high;
    int arr[];
    int n;
    Test()
    {
        n=5;
        arr = new int[n];
        arr[0] = 10;
        arr[1] = 20;
        arr[2] = 30;
        arr[3] = 40;
        arr[4] = 50;
        high = arr[0];
    }
    public static void main(String[] args)
    {
       Test t = new Test();
       t.findHigh(0);
       t.printHigh();
    }
    public void printHigh()
    {
        System.out.println("highest = "+high);
    }
    public void findHigh(int i)
    {
        if(i > n-1)
        {
            return;
        }
        if(arr[i] > high)
        {
            high = arr[i];
        }
        findHigh(i+1);
        return;
    }
}

вы можете сделать это рекурсивно следующим образом.

повторяющееся отношение это что-то вроде этого.

   f(a,n)   = a[n]   if n == size
            = f(a,n+1) if n != size

реализация выглядит следующим образом.

   private static int getMaxRecursive(int[] arr,int pos) {
         if(pos == (arr.length-1)) {
                return arr[pos];
         } else {           
                return Math.max(arr[pos], getMaxRecursive(arr, pos+1));
         }
   }

и вызов будет выглядеть так

      int maxElement = getMaxRecursive(arr,0);

Я знаю, что это старый нить, но, возможно, это помогает!

public static int max(int[] a, int n) {
        if(n < 0) {
            return Integer.MIN_VALUE;
        }
        return Math.max(a[n-1], max(a, n - 2));

    }

Не хорошо! ваш код не найдет максимальный элемент в массиве, он вернет только элемент, который имеет большее значение,чем элементы рядом с ним, для решения этой проблемы элемент максимального значения в диапазоне может быть передан в качестве аргумента для рекурсивного метода.

    private static int findMax(int[] a, int head, int last,int max) {
    if(last == head) {
        return max;
    }
    else if (a[head] > a[last]) {
            max = a[head];
            return findMax(a, head, last - 1, max);
        } else {
            max = a[last];
            return findMax(a, head + 1, last, max);
        }
}

  public int GetMax(int [] A, int index)  {

         index += 1;
         if (index >= A.Length) return 0;
         return Math.Max(A[index], GetMax(A, index + 1));

     }

int maximum = getMaxValue ( arr[arr.length - 1 ], arr, arr.length - 1 );

public static int getMaxValue ( int max, int arr[], int index )
{
    if ( index < 0 )
        return max;
    if ( max < arr[index] )
        max = arr[index];
    return getMaxValue ( max, arr, index - 1 ); 
}

Я чувствовал, что использование трекера для текущего максимального значения было бы хорошо.