web-dev-qa-db-fra.com

Trouver les minima locaux dans un tableau

É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?

27
devsda

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:

  1. S'il n'y a qu'un seul élément, il est garanti qu'il s'agit d'un minimum local.
  2. S'il y a plusieurs éléments, regardez l'élément du milieu. Si c'est un minimum local, vous avez terminé. Sinon, au moins un des éléments à côté doit être plus petit que lui. Maintenant, imaginez ce qui se passerait si vous commenciez par l’un des éléments les plus petits et que vous vous dirigiez progressivement vers l’une des extrémités du tableau dans la direction opposée à celle de l’élément central. A chaque étape, l’élément suivant est plus petit que le précédent ou sera plus gros. Finalement, vous atteindrez la fin du tableau de cette façon ou vous atteindrez un minimum local. Notez que cela signifie que vous pouvez faire ceci pour trouver un minimum local. Cependant, nous ne le ferons pas réellement. Au lieu de cela, nous utiliserons le fait qu’un minimum local existera dans cette moitié du tableau pour justifier l’abandon de la moitié du tableau. Dans ce qui reste, nous sommes assurés de trouver un minimum local.

Par conséquent, vous pouvez construire l'algorithme récursif suivant:

  1. S'il n'y a qu'un seul élément de tableau, c'est un minimum local.
  2. S'il y a deux éléments de tableau, cochez chacun d'eux. Il faut être un minimum local.
  3. Sinon, regardez l'élément central du tableau. Si c'est un minimum local, retournez-le. Sinon, au moins une valeur adjacente doit être inférieure à celle-ci. Recurse dans la moitié du tableau contenant cet élément plus petit (mais pas le milieu).

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.

57
templatetypedef

Le nombre de minima locaux peut être n/2; vous ne pouvez pas tous les énumérer dans O(log n) time.

6
foxcub

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).

5
Elad

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;
        }           
    }
}
}
0
Sohan

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.

0
jeffery.yuan

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]. 

0
user2316569

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;
        }
    }
}
0
Sohan