Trouver des minima locaux dans un tableau

avec un tableau de nombres entiers, trouver 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 des éléments limitrophes, le nombre doit être juste plus petit que le nombre adjacent.

je sais s'il n'y a qu'un minimum local, alors nous pouvons résoudre avec la recherche binaire modifiée. Mais si l'on sait qu'il existe plusieurs minima locaux dans le tableau, peut-il être résolu O(log n) temps?

26
demandé sur templatetypedef 2012-09-02 21:37:06

7 réponses

si les éléments du tableau ne sont pas garantis d'être distincts, alors 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 valeurs n > 1 sont les mêmes. Dans ce cas, aucun des éléments ne peut être minima locaux, car aucun élément n'est moins que ses voisins. Toutefois, afin de déterminer que toutes les valeurs sont les mêmes, vous avez à regarder tous les éléments du tableau, qui prend O(n) fois. Si vous utilisez moins de O(n) temps, vous ne pouvez pas nécessairement de tous les éléments du tableau.

si, d'un autre côté, les éléments du tableau sont garantis être distincts, vous pouvez résoudre cela en temps O(log n) en utilisant les observations suivantes:

  1. Si il n'y a qu'un élément, c'est la garantie d'un minimum local.
  2. s'il y a plusieurs éléments, regardez l'élément du milieu. Si c'est un minimum local, c'est fini. Dans le cas contraire, au moins un des éléments adjacents doit être plus petit que il. Maintenant, imaginez ce qui se passerait si vous commenciez par l'un des éléments plus petits et vous dirigiez progressivement vers l'une des extrémités du tableau dans la direction opposée à l'élément central. À chaque étape, soit l'élément suivant est plus petite que la précédente, ou il sera plus grand. Éventuellement, vous allez soit frapper la fin du tableau de cette façon, ou vous allez frapper un minimum local. Notez que cela signifie que vous faites ceci pour trouver un minimum local. Cependant, nous ne sommes pas en fait va faire ça. Au lieu de cela, nous utiliserons le fait qu'un minimum local existera dans cette moitié du tableau comme justification pour jeter une 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. On doit être un local. minimum.
  3. sinon, regardez l'élément central du tableau. Si c'est un minimum local, le retourner. Sinon, au moins une valeur adjacente doit être plus petite que celle-ci. Récurse dans la moitié du tableau contenant cet élément plus petit (mais pas le milieu).

notez que ceci a la relation récurrence

T (1) ≤ 1

T (2) ≤ 1

T (n) ≤ T (n / 2) + 1

Utilisation du Master Théorème, vous pouvez montrer que cet algorithme s'exécute dans le temps O(log n), Comme demandé.

Espérons que cette aide!

veuillez également noter que cet algorithme ne fonctionne que si les bords du tableau comptent comme minima locaux s'ils sont plus petits que l'élément adjacent.

56
répondu templatetypedef 2012-09-02 18:17:44

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

5
répondu foxcub 2012-09-02 17:44:45

utilisez un algorithme diviser pour mieux régner. Soit m = n / 2, et examiner la valeur A[m] (que est, l'élément dans le milieu du tableau).

Cas 1: A[m-1] < A[m]. Puis la moitié gauche du tableau doit contenir un minimum local, alors recurse sur la moitié gauche. Nous pouvons le montrer par contradiction: supposons Qu'un[i] n'est pas un minimum local pour chaque 0 ≤ i < m. Alors un[m-1] n'est pas un minimum local, ce qui implique Qu'un[m-2] < a[m-1]. De même, A[m -3] < a[m -2]. En continuant de cette manière, nous obtenir un[0] < A[1]. Mais alors un[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, alors revenez sur la moitié droite. C'est symétrique au cas 1.

cas 3: A[m - 1] > A[m] et A[M + 1] < A[m]. Alors un [m] est un minimum local, alors retournez-le. La récurrence du temps de fonctionnement est T(n) = T(n/2) + Θ(1), ce qui donne T(n) = Θ (log n).

5
répondu Elad 2014-01-20 17:33:50

la question originale n'est pas complète.

je viens de trouver la question complète et l'explication complète et détaillée à trouver les minima locaux dans un tableau! - pas mon blog

étant donné un tableau d'entiers uniques dont les deux premiers nombres diminuent et les deux derniers nombres augmentent, trouvez un nombre dans le tableau qui est des minima locaux. Un nombre dans le tableau s'appelle les minima locaux s'il est plus petit que ses nombres de gauche et de droite.

Pour exemple dans le tableau 9,7,2,8,5,6,3,4 2 est un minimum local car il est plus petit que son numéro gauche et droit 7 et 8. De même, 5 est un autre minimum local puisqu'il se situe entre 8 et 6, tous deux supérieurs à 5.

vous devez trouver l'un des minima locaux.

0
répondu jeffery.yuan 2014-07-11 17:08:59

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 de 12.. mais quand je coche l'élément du milieu, qui est 7, votre algorithme rejettera la moitié gauche (qui a les minima) et vérifiera la moitié droite. Par conséquent, il ne fonctionne pas

je pense qu'il ne fonctionne que pour le cas particulier où le tableau a une propriété particulière d'Un[1] ≥ A[2] et A[n - 1] ≤ A [n].

0
répondu user2316569 2014-07-21 07:02:26

Voici une solution qui fonctionne sur O(log n). Fondamentalement, cela fonctionne sur l'approche de tri de fusion (diviser pour mieux 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
répondu Sohan 2016-09-28 01:57:45

en fait, mon algorithme précédent peut être modifié pour obtenir toutes les maxima dans le 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
répondu Sohan 2016-09-28 05:38:49