Stratégies gloutonnes et recherche binaire pour l'optimisation de tableaux

Maximisation de la somme des hauteurs de tours distinctes

Le problème consiste à attribuer une hauteur à chaque tour de manière à ce que toutes les hauteurs soient strictement distinctes, tout en respectant une limite maximale pour chaque tour, et en maximisant la somme totale des hauteurs.

Approche algorithmique

L'approche gloutonne optimale repose sur le tri des limites de hauteur. En parcourant le tableau de la plus grande limite vers la plus petite, on attribue à chaque tour la hauteur maximale possible. Cette hauteur est déterminée par le minimum entre sa limite initiale et la hauteur de la tour précédemment traitée moins un. Si à un moment donné la hauteur calculée devient nulle ou négative, la configuration est impossible et l'algorithme retourne une erreur.

Analyse de la complexité

  • Complexité temporelle : O(N log N), dominée par l'opération de tri du tableau.
  • Complexité spatiale : O(1) ou O(log N) selon l'implémentation du tri, car aucune structure de données supplémentaire significative n'est requise.

Implémentation

class TowerHeightOptimizer {
    public long computeMaxSum(int[] limits) {
        Arrays.sort(limits);
        long accumulatedHeight = limits[limits.length - 1];
        int currentMaxAllowed = limits[limits.length - 1];

        for (int idx = limits.length - 2; idx >= 0; idx--) {
            currentMaxAllowed = Math.min(limits[idx], currentMaxAllowed - 1);
            if (currentMaxAllowed <= 0) {
                return -1;
            }
            accumulatedHeight += currentMaxAllowed;
        }
        return accumulatedHeight;
    }
}

Rendre un tableau unique avec des incréments minimaux

L'objectif est de rendre tous les éléments d'un tableau uniques en effectuant le nombre minimum d'incréments sur les valeurs existantes.

Approche algorithmique

Après un tri ascendant du tableau, on parcourt les éléments en s'assurant que chaque valeur est strictement supérieure à la précédente. Si l'élément courant est inférieur ou égal à l'élément ajusté précédent, on l'incrémente jusqu'à atteindre valeur_précédente + 1. La différence entre la nouvelle valeur valide et l'ancienne est ajoutée au compteur total de mouvements. Cette méthode garantit que chaque élément trouve sa position unique la plus proche possible de sa valeur d'origine.

Analyse de la complexité

  • Complexité temporelle : O(N log N), le goulot d'étranglement étant l'étape de tri.
  • Complexité spatiale : O(1), l'ajustement se fait en place ou avec une variable d'état minimale.

Implémentation

class UniqueArrayAdjuster {
    public int calculateMinIncrements(int[] elements) {
        Arrays.sort(elements);
        int totalMoves = 0;
        int previousValue = elements[0];

        for (int idx = 1; idx < elements.length; idx++) {
            if (elements[idx] <= previousValue) {
                int nextValidValue = previousValue + 1;
                totalMoves += nextValidValue - elements[idx];
                previousValue = nextValidValue;
            } else {
                previousValue = elements[idx];
            }
        }
        return totalMoves;
    }
}

Maximiser l'élément après réduction et réarrangement

Le but est de maximiser l'élément le plus grand d'un tableau après l'avoir réarrangé, sous deux contraintes strictes : le premier élément doit être 1, et la différence absolue entre deux éléments adjacents ne doit pas dépasser 1.

Approche algorithmique

Le tri permet de traiter les éléments dans un ordre prévisible. On force le premier élément à 1 pour satisfiare la première contrainte. Pour les éléments suivants, on utilise une fonction minimum pour borner leur valeur à élément_précédent + 1. Cela garantit que la condition d'adjacence est respectée tout en conservant les valeurs aussi grandes que possible, maximisant ainsi le dernier élément du tableau.

Analyse de la complexité

  • Complexité temporelle : O(N log N) due au tri initial.
  • Complexité spatiale : O(1) pour les variables auxiliaires.

Implémentation

class ArrayRearranger {
    public int findMaxElement(int[] sequence) {
        Arrays.sort(sequence);
        sequence[0] = 1;

        for (int idx = 1; idx < sequence.length; idx++) {
            sequence[idx] = Math.min(sequence[idx], sequence[idx - 1] + 1);
        }
        return sequence[sequence.length - 1];
    }
}

Comptage maximal de points dans un carré avec étiquettes uniques

Ce problème demande de trouver le nombre maximum de points pouvant être contenus dans un carré centré à l'origine, tel que chaque point à l'intérieur du carré possède une étiquette de chaîne de caractères unique.

Approche algroithmique

Une recherche binaire est appliquée sur la taille du carré (définie par la distance maximale par rapport à l'origine sur les axes X et Y). Pour chaque taille candidate évaluée via le point médian, une fonction de validation vérifie si tous les points inclus ont des étiquettes uniques à l'aide d'un tableau de suivi booléen. Si des doublons sont détectés, la taille est réduite ; sinon, le nombre de points est enregistré et on tente d'agrandir le carré.

Analyse de la complexité

  • Complexité temporelle : O(N log M), où N est le nombre de points et M est la coordonnée maximale absolue. La recherche binaire prend O(log M) et chaque validation prend O(N).
  • Complexité spatiale : O(1) ou O(Σ) où Σ est la taille de l'alphabet (26 pour les lettres minuscules), pour le tableau de suivi des caractères.

Implémentation

class SquarePointCounter {
    public int maxPointsInSquare(int[][] coords, String labels) {
        int maxCoordinate = 0;
        for (int[] p : coords) {
            maxCoordinate = Math.max(maxCoordinate, Math.max(Math.abs(p[0]), Math.abs(p[1])));
        }

        int low = 0, high = maxCoordinate;
        int bestCount = 0;

        while (low <= high) {
            int mid = low + (high - low) / 2;
            int currentCount = validateAndCount(coords, labels, mid);
            
            if (currentCount != -1) {
                bestCount = Math.max(bestCount, currentCount);
                low = mid + 1;
            } else {
                high = mid - 1;
            }
        }
        return bestCount;
    }

    private int validateAndCount(int[][] pts, String lbls, int size) {
        int seen = 0;
        boolean[] charTracker = new boolean[26];

        for (int i = 0; i < pts.length; i++) {
            int distX = Math.abs(pts[i][0]);
            int distY = Math.abs(pts[i][1]);

            if (distX <= size && distY <= size) {
                int charIdx = lbls.charAt(i) - 'a';
                if (charTracker[charIdx]) {
                    return -1; 
                }
                charTracker[charIdx] = true;
                seen++;
            }
        }
        return seen;
    }
}

Étiquettes: algorithme-glouton Recherche-Binaire optimisation-tableau leetcode complexite-algorithmique

Publié le 16 septembre à 04h34