Étant donné un tableau d'entiers, recherchez les minima locaux. Un élément A [i] est défini comme un minimum local si A [i-1]> A [i] et A [i] <A [i + 1] où i = 1 ... n-2. Dans le cas d'éléments limites, le nombre doit être juste inférieur au nombre adjacent.
Je sais que s’il ya un seul minimum local, nous pouvons résoudre la recherche binaire modifiée . Mais s’il est avéré qu’il existe plusieurs minima locaux dans le tableau, peut-on le résoudre en O(log n)
temps?
S'il n'est pas garanti que les éléments du tableau soient distincts, il n'est pas possible de le faire en temps O (log n). La raison en est la suivante: supposons que vous ayez un tableau où toutes les n> 1 valeurs sont identiques. Dans ce cas, aucun des éléments ne peut être un minimum local, car aucun élément n'est inférieur à ses voisins. Cependant, pour déterminer que toutes les valeurs sont identiques, vous devrez examiner tous les éléments du tableau, ce qui prend O(n) temps. Si vous utilisez moins de O(n) fois, vous ne pouvez pas nécessairement consulter tous les éléments du tableau.
Si, en revanche, les éléments du tableau sont garantis distincts, vous pouvez résoudre ce problème en un temps O (log n) en utilisant les observations suivantes:
Par conséquent, vous pouvez construire l'algorithme récursif suivant:
Notez que cela a la relation de récurrence
T (1) ≤ 1
T (2) ≤ 1
T (n) ≤ T (n/2) + 1
En utilisant le théorème principal, vous pouvez montrer que cet algorithme s'exécute dans le temps O (log n), selon les besoins.
J'espère que cela t'aides!
Veuillez également noter que cet algorithme ne fonctionne que si les bords du tableau comptent comme des minima locaux s'ils sont plus petits que l'élément adjacent.
Le nombre de minima locaux peut être n/2
; vous ne pouvez pas tous les énumérer dans O(log n)
time.
Utilisez un algorithme diviser pour régner. Soit m = n/2 et examinons la valeur A [m] (thatis, l’élément situé au milieu du tableau).
Cas 1: A [m − 1] <A [m]. Ensuite, la moitié gauche du tableau doit contenir un minimum local, donc recurse sur la moitié gauche. Nous pouvons montrer cela par contradiction: supposons que A [i] ne soit pas un minimum local pour chaque 0 ≤ i <m. Alors A [m-1] n'est pas un minimum local, ce qui implique que A [m-2] <A [m-1]. De même, A [m −3] <A [m −2]. En continuant ainsi, nous obtenons A [0] <A [1]. Mais alors [0] est un minimum local, contrairement à notre hypothèse initiale.
Cas 2: A [m + 1]> A [m]. Ensuite, la moitié droite du tableau doit contenir un minimum local, donc Recurse sur la moitié droite. Ceci est symétrique au cas 1.
Cas 3: A [m - 1]> A [m] et A [m + 1] <A [m]. Alors A [m] est un minimum local, alors renvoyez-le . La récurrence de l'heure d'exécution est T(n) = T(n/2) + Θ (1), ce qui donne T(n) = Θ (log n).
En fait, mon algorithme précédent peut être modifié pour obtenir tous les maxima en temps O (log n). J'ai testé que cela fonctionne très bien pour toutes les entrées fournies. S'il vous plaît laissez-moi savoir vos commentaires
public class LocalMaximas {
@Test
public void test () {
System.out.println("maximas: please modify code to handle if array size is <= 2");
int []a = {5,8,10,25,6,3,44,51,55,56,57,58,34,5,59,2};
localMaximas(a);
int []b = {9,7,2,8,5,6,3,4, 2}; //9,8,6,4
localMaximas(b);
int [] c= {15, 13, 12, 18, 19, 20, 7, 6, 5, 4, 3, 2, 1};//15,20
localMaximas(c);
}
public void localMaximas (int [] a) {
System.out.println("\n\n");
if(isMaxima(a,0)) {
System.out.println(a[0]);
}
if(isMaxima(a,a.length-1)) {
System.out.println(a[a.length-1]);
}
localMaximas(a,0,a.length-1);
}
int localMaximas(int []a,int low, int high) {
int mid = (low+high)/2;
if(high-low > 3) { // more than 4 items in currently divided array
if(isMaxima(a,mid)) {
System.out.println(a[mid]);
}
localMaximas(a,low, mid);
localMaximas(a,mid, high);
}
else if(high-low == 3){ //exactly 4 items in currently divided array
localMaximas(a,low, mid+1);
localMaximas(a,mid, high);
}
else if((high-low == 2) && (isMaxima(a,low+1))) {
System.out.println(a[low+1]);
}
return 0;
}
int maxof(int []a, int i, int j) {
if(a[i] <a[j]) {
return j;
}
else {
return i;
}
}
boolean isMaxima(int []a ,int mid) {
if(mid == 0) {
if(maxof(a, mid, mid+1) == mid) {
return true;
}
else {
return false;
}
}
else if(mid==a.length-1) {
if(maxof(a,mid,mid-1) == mid) {
return true;
}
else {
return false;
}
}
else {
if((maxof(a, mid, mid+1) == mid) && (maxof(a, mid, mid-1) == mid)) {
return true;
}
else {
return false;
}
}
}
}
La question initiale n'est pas complète.
Je viens de trouver la question complète et une explication détaillée à l'adresse Trouver les minima locaux dans un tableau ! - pas mon blog
Étant donné un tableau d'entiers uniques dont les deux premiers nombres sont décroissants et les deux derniers nombres croissants, trouvez un nombre dans le tableau qui correspond à des minima locaux. Un nombre dans le tableau est appelé minimum local s'il est plus petit que ses nombres gauche et droit.
Par exemple, dans le tableau, 9,7,2,8,5,6,3,4 2 est un minimum local, car il est plus petit que ses chiffres gauche et droit 7 et 8. est compris entre 8 et 6, tous deux supérieurs à 5.
Vous devez trouver l'un des minima locaux.
Votre algorithme ne fonctionnera pas pour ce tableau
15, 13, 12, 18, 19, 20, 7, 6, 5, 4, 3, 2, 1
Ici, le minimum local est 12 .. mais quand je vérifie l’élément du milieu, qui est 7, l’algorithme jette la moitié gauche (qui a le minimum) et vérifie la moitié droite. Donc ça ne marche pas
Je pense que cela ne fonctionnera que dans le cas particulier où le tableau a une propriété spéciale telle que A [1] ≥ A [2] et A [n - 1] ≤ A [n].
Voici une solution qui fonctionne sur O (log n). Fondamentalement, cela fonctionne sur l’approche de tri par fusion (diviser pour régner).
public class LocalMaxima {
int []a = {5,8,10,25,6,3,44,51,55,56,57,58,34,5,59};
@Test
public void localMaxima () {
System.out.println((a[localMaxima(0,a.length-1)]));
}
int localMaxima(int low, int high) {
if(high-low > 2) {
int mid = (low+high)/2;
return maxof(localMaxima(low,mid),localMaxima(mid+1, high));
}
else if(high-low == 1) {
return maxof(high,low);
}
else if(high-low == 0) {
return high;
}
if(high-low == 2) {
return maxof(maxof(low, high),low+1);
}
return 0;
}
int maxof(int i, int j) {
if(a[i] <a[j]) {
return j;
}
else {
return i;
}
}
}