Pour l'une des questions que l'on m'a demandé de résoudre, j'ai trouvé la valeur maximale d'un tableau à l'aide d'une boucle for, j'ai donc essayé de le trouver à l'aide de la récursivité et voici ce que j'ai proposé:
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];
}
}
Donc, cela fonctionne bien et obtient la valeur maximale, mais ma question est la suivante: est-il correct d’avoir pour le cas de base un retour [tête] et pour le cas où la valeur à la tête est> la dernière valeur?
Vous pouvez tout aussi facilement le faire avec un seul compteur, juste l'index de la valeur que vous voulez comparer cette fois:
public static int findMax(int[] a, int index) {
if (index > 0) {
return Math.max(a[index], findMax(a, index-1))
} else {
return a[0];
}
}
Cela montre beaucoup mieux ce qui se passe et utilise la disposition par défaut "récursivité", par exemple. avec un pas de base commun. L'appel initial est en faisant findMax(a, a.length-1)
.
C'est en fait beaucoup plus simple que cela. Le cas de base est si vous avez atteint la fin du tableau (la partie "else" du bloc de contrôle ternaire ci-dessous). Sinon, vous renvoyez le maximum de l'appel en cours et de l'appel récursif.
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;
}
À chaque élément, vous retournez le plus grand de l'élément actuel et tous les éléments avec un plus grand index. Integer.MIN_VALUE
sera retourné uniquement sur des tableaux vides. Cela se passe dans le temps linéaire.
Je résoudrais ceci en divisant le tableau en deux lors de chaque appel récursif.
findMax(int[] data, int a, int b)
où a et b sont des indices de tableau.
La condition d'arrêt est quand b - a <= 1
, alors ce sont des voisins et le max est max (a, b);
L'appel initial:
findMax(int[] data, int 0, data.length -1);
Cela réduit la profondeur de récursivité maximale de N à log2 (N).
Mais l’effort de recherche reste toujours O (N).
Cela se traduirait par
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);
}
}
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;
}
}
Je suis tombé sur ce fil et cela m'a beaucoup aidé. Ci-joint, mon code complet dans les cas de récursivité et de division/conquête. Le temps d’exécution de divide & conquer est légèrement meilleur que la récursivité.
//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));
}
Je sais que c'est un vieux fil, mais peut-être que ça aide!
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));
}
Qu'en est-il de celui-ci?
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;
}
Solution optimisée
public class Test1 {
public static int findMax(int[] a, int head, int last) {
int max = 0, max1 = 0;
if (head == last) {
return a[head];
} else if (a[head] < a[last]) {
max = findMax(a, head + 1, last);
} else
max = findMax(a, head, last - 1);
if (max >= max1) {
max1 = max;
}
return max1;
}
public static void main(String[] args) {
int arr[] = {1001, 0, 2, 1002, 2500, 3, 1000, 7, 5, 100};
int i = findMax(arr, 0, 9);
System.out.println(i);
}
}
Vous pouvez le faire de manière récursive comme suit.
Relation récurrente c'est quelque chose comme ça.
f(a,n) = a[n] if n == size
= f(a,n+1) if n != size
La mise en œuvre est la suivante.
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));
}
}
et appel va ressembler à ceci
int maxElement = getMaxRecursive(arr,0);
ce n'est pas correct! votre code ne trouvera pas l'élément maximum dans le tableau, il retournera uniquement l'élément qui a une valeur supérieure à celle des éléments adjacents, pour résoudre ce problème, l'élément de valeur maximum dans l'intervalle peut être passé comme argument pour la méthode récursive.
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));
}