L'algorithme glouton le plus compréhensible

1. Explication de l'algorithme

Comme son nom l'indique, l'algorithme glouton ou la pensée gloutonne adopte une stratégie gloutonne pour garantir que chaque opération est localement optimale, de sorte que le résultat final soit globalement optimal.


Pour donner un exemple simple : Xiao Ming et Xiao Wang aiment manger des pommes, Xiao Ming peut manger cinq pommes et Xiao Wang peut manger trois pommes. On sait qu'il y a une infinité de pommes dans le verger de pommiers, demandez à Xiao Ming et Xiao Wang combien de pommes ils peuvent manger au maximum.


Dans cet exemple, la stratégie gourmande que nous pouvons choisir est que chaque personne mange le nombre maximum de pommes qu’il peut manger, ce qui est localement optimal pour chaque personne. Et parce que le résultat global est une simple somme de résultats locaux et que les résultats locaux ne sont pas pertinents les uns par rapport aux autres, la stratégie localement optimale est également la stratégie globalement optimale.


2. Problème de distribution

2.1. Diffusion des cookies

2.1.1, description du sujet

455. Distribuer des cookies

Disons que vous êtes un parent formidable et que vous souhaitez offrir des petits cookies à vos enfants. Cependant, chaque enfant ne reçoit pas plus d'un cookie.

Pour chaque enfant i, il existe une valeur d'appétit g[i], qui est la plus petite taille de biscuit pouvant satisfaire l'appétit de l'enfant ; et chaque biscuit ja une taille s[j]. Si s[j] >= g[i]nous pouvons jdistribuer ce cookie à un enfant i, l'enfant sera satisfait. Votre objectif est de satisfaire le plus grand nombre d'enfants possible et de produire cette valeur maximale.

2.1.2. Exemples d'entrées et de sorties

Exemple 1 :
Entrée : g = [1, 2, 3], s = [1, 1]
Sortie : 1
Explication :
Vous avez trois enfants et deux biscuits, et les valeurs d'appétit des trois enfants sont : 1, 2 , 3.
Même si vous disposez de deux petits biscuits, comme ils ont tous deux une taille de 1, vous ne pouvez satisfaire qu'un enfant ayant une valeur d'appétit de 1.
Vous devriez donc sortir 1.

Exemple 2 :
Entrée : g = [1, 2], s = [1, 2, 3]
Sortie : 2
Explication :
Vous avez deux enfants et trois biscuits, et les valeurs d'appétit des deux enfants sont respectivement de 1 et 2 .
Vous disposez de suffisamment de cookies en quantité et en taille pour satisfaire tous les enfants.
Vous devriez donc sortir 2.

2.1.3.Solution

Parce que l’enfant qui a le moins faim est le plus susceptible d’être rassasié, nous considérons cet enfant en premier. Afin que les biscuits restants satisfassent autant que possible l'enfant ayant une plus grande faim, nous devons donner à l'enfant le biscuit de la plus petite taille supérieure ou égale à sa faim. Après avoir satisfait cet enfant, nous adoptons la même stratégie et considérons l'enfant ayant le moins faim parmi les enfants restants jusqu'à ce qu'il n'y ait plus de cookies satisfaisants.


En bref, la stratégie gourmande consiste ici à attribuer le plus petit biscuit plein à l’enfant qui a le moins faim parmi les enfants restants. En ce qui concerne l'implémentation spécifique, comme nous devons obtenir la relation de taille, un moyen pratique consiste à trier les enfants et les cookies séparément. De cette façon, nous pouvons partir de l’enfant ayant la plus petite faim et du biscuit ayant la plus petite taille, et calculer combien de paires peuvent satisfaire à la condition.

class Solution {
    
    
    public int findContentChildren(int[] g, int[] s) {
    
    
        Arrays.sort(g);
        Arrays.sort(s);
        int child = 0, cookie = 0;
        // 优先给最小饥饿度的孩子分配最小的饼干
        while (child < g.length && cookie < s.length) {
    
    
            if (g[child] <= s[cookie]) {
    
    
                child++;
            }
            cookie++;
        }
        return child;
    }
}

Analyse de complexité

  • Complexité temporelle : O(mlogm+nlogn) , où m et n sont respectivement les longueurs des tableaux g et s. La complexité temporelle du tri de deux tableaux est O(mlogm + nlogn), et la complexité temporelle du parcours des tableaux est O(m+n), donc la complexité temporelle totale est O(mlogm + nlogn).
  • Complexité spatiale : O(logm+logn) , où m et n sont respectivement les longueurs des tableaux g et s. La complexité spatiale est principalement due à la surcharge d'espace supplémentaire liée au tri.

2.2. Distribution de bonbons

2.2.1, description du sujet

135. Distribution de bonbons.

n Les enfants se mettent en rang. Vous recevez un tableau d'entiers ratingsreprésentant la note de chaque enfant.

Vous devez distribuer des bonbons à ces enfants selon les exigences suivantes :

  • Chaque enfant reçoit au moins 1des bonbons.
  • L'enfant ayant le score le plus élevé parmi deux enfants adjacents reçoit plus de bonbons.

Merci de distribuer des bonbons à chaque enfant, de calculer et de restituer le nombre minimum de bonbons à préparer .

2.2.2. Exemple d'entrée et de sortie

Exemple 1 :
Entrée : notes = [1, 0, 2]
Sortie : 5
Explication : Vous pouvez distribuer 2, 1 et 2 bonbons respectivement au premier, au deuxième et au troisième enfant.

Exemple 2 :
Entrée : notes = [1, 2, 2]
Sortie : 4
Explication : Vous pouvez distribuer respectivement 1, 2 et 1 bonbon au premier, au deuxième et au troisième enfant.
    Le troisième enfant ne reçoit qu'un seul bonbon, qui remplit les deux conditions du titre.

2.2.3.Solution

Après avoir abordé 2.1、分发饼干le sujet, pensez-vous que les stratégies avides avec des relations comparatives doivent être triées ou sélectionnées ? Bien que cette question utilise également une stratégie gourmande, nous n'avons besoin que de deux parcours simples : initialiser le nombre de bonbons de tous les enfants à 1 ; parcourir de gauche à droite en premier, si l'enfant de droite a un score plus élevé que celui de gauche. , puis le nombre de bonbons de l'enfant de droite est mis à jour au nombre de bonbons de l'enfant de gauche plus 1 ; puis parcourir de droite à gauche, si le score de l'enfant de gauche est supérieur à celui de droite, et le nombre actuel de bonbons de l'enfant de gauche n'est pas supérieur au nombre de bonbons de l'enfant de droite, alors celui de gauche Le nombre de bonbons de l'enfant est mis à jour au nombre de bonbons de l'enfant de droite plus 1. Grâce à ces deux parcours, les bonbons alloués peuvent répondre aux exigences du sujet. La stratégie gourmande ici est que dans chaque parcours, seule la relation de taille du côté adjacent est prise en compte et mise à jour.


Comme 示例1dans, nous initialisons la distribution candy comme [1,1,1], le résultat après la première mise à jour du parcours est [1,1,2] et le résultat après la deuxième mise à jour du parcours est [2,1,2] .

class Solution {
    
    
    public int candy(int[] ratings) {
    
    
        // 每个孩子至少一颗糖果
        int candyCount = ratings.length;
        // 用于记录每个孩子需要评分需要额外奖励的糖果数量
        int[] candyArr = new int[ratings.length];
        
        // 从左往右遍历一遍,如果右边孩子的评分比左边的高,则右边孩子的糖果数更新为左边孩子的糖果数加 1
        for (int i = 1; i < ratings.length; i++) {
    
    
            if (ratings[i] > ratings[i - 1]) {
    
    
                candyArr[i] = candyArr[i - 1] + 1;
                candyCount += candyArr[i];
            }
        }
        
        /*
         * 从右往左遍历一遍,如果左边孩子的评分比右边的高,
         * 且左边孩子当前的糖果数不大于右边孩子的糖果数(排除上面从左往右遍历过程中已追加的糖果数量影响),
         * 则左边孩子的糖果数更新为右边孩子的糖果数加 1
         */
        for (int i = ratings.length - 2; i >= 0; i--) {
    
    
            if (ratings[i] > ratings[i + 1] && candyArr[i] <= candyArr[i + 1]) {
    
    
                // 因该位置孩子的糖果数量较上次遍历又发生了变化,会导致重复计算,故需减去之前的数量,重新计算
                candyCount -= candyArr[i];
                candyArr[i] = candyArr[i + 1] + 1;
                candyCount += candyArr[i];
            }
        }
        return candyCount;
    }
}

Analyse de complexité

  • Complexité temporelle : O(n) , où n est le nombre d'enfants. Nous devons parcourir le tableau deux fois pour calculer le nombre minimum de bonbons qui satisfont respectivement au parcours de gauche à droite et de droite à gauche.
  • Complexité spatiale : O(n) , où n est le nombre d’enfants. Il faut mémoriser le nombre de bonbons attribués à chaque enfant lors des deux traversées.

3. Problème d'intervalle

3.1. Pas d'intervalle de chevauchement

3.1.1, description du sujet

435. Intervalles sans chevauchement

Étant donné une collection d'intervalles intervals, où intervals[i] = [starti, endi]. Renvoie le nombre minimum d'intervalles qui doivent être supprimés afin que les intervalles restants ne se chevauchent pas.

3.1.2. Exemple d'entrée et de sortie

Exemple 1 :
Entrée : intervalles = [ [1, 2], [2, 3], [3, 4], [1, 3] ] Sortie :
1 Explication
: Après avoir supprimé [1,3], l'intervalle restant Il y a pas de chevauchement.

Exemple 2 :
Entrée : intervalles = [ [1, 2], [1, 2], [1, 2] ]
Sortie : 2
Explication : Vous devez supprimer deux [1,2] pour que les intervalles restants ne se chevauchent pas.

Exemple 3 :
Entrée : intervalles = [ [1, 2], [2, 3] ]
Sortie : 0
Explication : Vous n'avez pas besoin de supprimer des intervalles car ils ne se chevauchent déjà pas.

3.1.3, solution au problème

La fin de l'intervalle est très importante lors du choix de l'intervalle à conserver : plus la fin de l'intervalle sélectionné est petite, plus il reste d'espace pour les autres intervalles, et plus il est possible de conserver d'intervalles. Par conséquent, la stratégie gloutonne que nous adoptons est de donner la priorité aux intervalles retenus avec des terminaisons petites et disjointes.


La méthode spécifique de mise en œuvre consiste à trier d'abord les intervalles par ordre croissant en fonction de la taille de la fin, et à sélectionner à chaque fois l'intervalle ayant la plus petite extrémité et qui ne chevauche pas l'intervalle précédemment sélectionné. Ici, Lambda de Java est utilisé pour le tri personnalisé.


Dans 示例1, le tableau trié est [[1,2], [2,3], [1,3], [3,4]]. Selon notre stratégie gloutonne, initialiser d'abord à l'intervalle [1,2] ; puis [2,3] ne coupe pas [1,2], puis le conserver ; car [1,3] coupe [2,3] , sauter L'intervalle ; puisque [3,4] ne coupe pas [2,3], il est conservé. Par conséquent, l'intervalle réservé final est [[1,2], [2,3], [3,4]].

class Solution {
    
    
    public int eraseOverlapIntervals(int[][] intervals) {
    
    
        if (intervals.length <= 0) {
    
    
            return 0;
        }
        // 将区间按照结尾的大小进行增序排序
        List<int[]> intervalList = Arrays.stream(intervals).sorted(Comparator.comparingInt(interval -> interval[1])).collect(Collectors.toList());
        int ans = 0;
        for (int preIndex = 0, i = 1; i < intervalList.size(); i++) {
    
    
            // 比较后一个区间开始是否在前一个区间内即可
            if (intervalList.get(i)[0] < intervalList.get(preIndex)[1]) {
    
    
                ans++;
                continue;
            }
            preIndex = i;
        }
        return ans;
    }
}

Analyse de complexité

  • Complexité temporelle : O(nlogn) , où n est le nombre d’intervalles. Nous avons besoin d'un temps O(nlogn) pour trier tous les intervalles par ordre croissant en fonction du bon point final, et d'un temps O(n) pour parcourir. Puisque le premier est asymptotiquement plus grand que le second, la complexité temporelle totale est O(nlogn).
  • Complexité de l'espace : O(logn) , qui est l'espace de pile requis pour le tri.

4. Pratique

4.1. Difficulté de base

4.1.1. Le problème de la plantation de fleurs

4.1.1.1, description du sujet

605. Le problème de la plantation de fleurs

Supposons qu'il y ait un très long parterre de fleurs et que certaines parcelles soient plantées de fleurs, mais l'autre partie ne l'est pas. Cependant, les fleurs ne peuvent pas être plantées sur des parcelles adjacentes, elles entreront en compétition pour l'eau et toutes deux mourront.

Vous recevez un tableau de parterres de fleurs entiers pour représenter un parterre de fleurs, composé de plusieurs 0 et 1, où 0 signifie qu'aucune fleur n'est plantée et 1 signifie que des fleurs sont plantées. Il existe un autre chiffre n, peut-on planter n fleurs sans enfreindre les règles de plantation ? Renvoie vrai si oui, faux si non.

4.1.1.2, exemple d'entrée et de sortie

Exemple 1 :
Entrée : parterre de fleurs = [1, 0, 0, 0, 1], n = 1
Sortie : vrai

Exemple 2 :
Entrée : parterre de fleurs = [1, 0, 0, 0, 1], n = 2
Sortie : faux

4.1.1.3, solution au problème

D'un point de vue gourmand, il faut planter autant de fleurs que possible sans enfreindre les règles de plantation, puis juger si le nombre maximum de fleurs pouvant être plantées est supérieur ou égal à n ; Combien de fleurs sont plantées, donc peut être optimisé dans la boucle.Lorsque le nombre de fleurs pouvant être plantées a atteint n, il peut être renvoyé directement sans continuer à calculer le reste du tableau.

class Solution {
    
    
    public boolean canPlaceFlowers(int[] flowerbed, int n) {
    
    
        for (int i = 0; i < flowerbed.length && n > 0; i++) {
    
    
            if (flowerbed[i] == 0 && (i == 0 || flowerbed[i - 1] == 0)
                    && (i == flowerbed.length - 1 || flowerbed[i + 1] == 0)) {
    
    
                n--;
                flowerbed[i] = 1;
            }
        }
        return n == 0;
    }
}

Analyse de complexité

  • Complexité temporelle : O(n) , où n est la longueur du parterre de fleurs du tableau. Le tableau doit être parcouru une fois.
  • Complexité spatiale : O(1) . L’espace supplémentaire utilisé est constant.

4.1.2. Faire exploser le ballon avec le moins de flèches

4.1.2.1, description du sujet

452. Exploser des ballons avec un nombre minimum de flèches

Il y a des ballons sphériques attachés à un mur représenté par un plan XY. Les ballons sur le mur sont enregistrés dans un tableau d'entiers points, où points[i] = [xstart, xend]représente les ballons dont le diamètre horizontal est compris entre xstartet . xendVous ne connaissez pas la coordonnée y exacte du ballon.

Un arc et une flèche peuvent être tirés parfaitement verticalement à partir de différents points le long de l’axe x. xstartTirez une flèche à la coordonnée x, s'il y a un ballon dont le diamètre commence et se termine aux coordonnées xendet satisfait xstart ≤ x ≤ xend, alors le ballon explosera . Il n'y a pas de limite au nombre d'arcs pouvant être tirés . Une fois l’arc et la flèche tirés, ils peuvent avancer indéfiniment.

Étant donné un tableau , renvoie le nombre minimumpoints de flèches qui doivent être tirées pour faire exploser tous les ballons .

4.1.2.2, exemple d'entrée et de sortie

Exemple 1 :
Entrée : points = [ [10, 16], [2, 8], [1, 6], [7, 12] ] Sortie : 2 Explication : Le ballon peut
être éclaté
avec 2 flèches :
○ en x = Tirez des flèches depuis 6 endroits et brisez les ballons [2,8] et [1,6].
○ Tirez la flèche en x = 11 et brisez les ballons [10,16] et [7,12].

Exemple 2 :
Entrée : points = [ [1, 2], [3, 4], [5, 6], [7, 8] ] Sortie : 4 Explication
: Chaque
ballon doit tirer une flèche, un total de 4 sont flèche nécessaire.

Exemple 3 :
Entrée : points = [ [1, 2], [2, 3], [3, 4], [4, 5] ] Sortie : 2 Explication
: Le
ballon peut être éclaté avec 2 flèches :
○ en x = Tirez des flèches à 2 endroits, brisant les ballons [1,2] et [2,3].
○ Tirez la flèche en x = 4 et brisez les ballons [3,4] et [4,5].

4.1.2.3, solution au problème

Cette question est 3.1、无重叠区间très similaire à , et elle adopte également une stratégie gourmande. Triez d'abord les intervalles par ordre croissant en fonction de la taille de l'extrémité, puis vérifiez si l'arc et la flèche qui ont fait exploser le ballon se déplacent vers la limite la plus à droite, et si le prochain ballon à intervalle peut exploser.


La méthode d'implémentation spécifique consiste à trier d'abord les intervalles par ordre croissant en fonction de la taille de la fin.Ici, Java Lambda est utilisé pour le tri personnalisé. Ensuite, prédéfinissez d'abord un arc et une flèche pour chaque intervalle, puis parcourez tous les ballons de l'intervalle, envisagez de déplacer l'arc et la flèche qui ont fait exploser le ballon vers la limite la plus à droite de l'intervalle et vérifiez s'ils chevauchent le ballon dans l'intervalle suivant. , ce qui peut sauver un arc et une flèche.

class Solution {
    
    
    public int findMinArrowShots(int[][] points) {
    
    
        // 最多需要的弓箭数
        int ans = points.length;
        // 将区间按照结尾的大小进行增序排序
        List<int[]> pointList = Arrays.stream(points).sorted(Comparator.comparingInt(point -> point[1])).collect(Collectors.toList());
        int preIndex = 0;
        for (int i = 1; i < pointList.size(); i++) {
    
    
            // 比较后一个区间是否和前一个区间重叠,重叠则可节约一支弓箭
            if (pointList.get(i)[0] <= pointList.get(preIndex)[1]) {
    
    
                ans--;
                continue;
            }
            preIndex = i;
        }
        return ans;
    }
}

Analyse de complexité

  • Complexité temporelle : O(nlogn) , où n est la longueur des points du tableau. La complexité temporelle du tri est O(nlogn), et la complexité temporelle du parcours de toutes les bulles et du calcul de la réponse est O(n), qui est asymptotiquement plus petite que la première, elle peut donc être ignorée.
  • Complexité de l'espace : O(logn) , qui est l'espace de pile requis pour le tri.

4.1.3. Diviser les intervalles de lettres

4.1.3.1, description du sujet

763. Diviser les intervalles alphabétiques

Une chaîne Sse compose de lettres minuscules. Nous devons diviser cette chaîne en autant de fragments que possible, et la même lettre apparaît dans au plus un fragment. Renvoie une liste représentant la longueur de chaque fragment de chaîne.

4.1.3.2. Exemple d'entrée et de sortie

Exemple 1 :
Entrée : S = "ababcbacadefegdehijhklij"
Sortie : [9, 7, 8]
Explication :
Le résultat de la division est "ababcbacaca", "defegde", "hijhklij".
Chaque lettre apparaît dans au plus un fragment.
Les divisions comme "ababcbacadefegde", "hijhklij" sont fausses car le nombre de divisions est moindre.

4.1.3.3, solution du problème

Puisque la même lettre ne peut apparaître que dans le même fragment, il est évident que la position en indice de la première occurrence et de la dernière occurrence de la même lettre doit apparaître dans le même fragment. Par conséquent, il est nécessaire de parcourir la chaîne pour obtenir la position en indice de la dernière occurrence de chaque lettre.


Après avoir obtenu la position en indice de la dernière occurrence de chaque lettre, une méthode gourmande peut être utilisée pour diviser la chaîne en autant de segments que possible. La méthode spécifique consiste à parcourir la chaîne de gauche à droite pour obtenir la valeur maximale de la dernière occurrence de toutes les lettres du segment actuel. Lorsque l'on accède à la fin de l'indice, l'accès au segment actuel se termine et la recherche du suivant Le segment continue jusqu'à ce que la chaîne soit parcourue.

class Solution {
    
    
    public List<Integer> partitionLabels(String s) {
    
    
        // 统计每个字母最后一次出现的下标位置
        int[] last = new int[26];
        for (int i = 0; i < s.length(); i++) {
    
    
            last[s.charAt(i) - 'a'] = i;
        }
        List<Integer> partition  = new ArrayList<>();
        int start = 0, end = 0;
        // 从左到右遍历字符串,获取当前片段所有字母最后一次出现的最大值end
        for (int i = 0; i < s.length(); i++) {
    
    
            end = Math.max(last[s.charAt(i) - 'a'], end);
            // 当访问到下标end时,当前片段访问结束
            if (i == end) {
    
    
                partition .add(end - start + 1);
                start = end + 1;
            }
        }
        return partition ;
    }
}

Analyse de complexité

  • Complexité temporelle : O(n) , où n est la longueur de la chaîne. Il est nécessaire de parcourir la chaîne deux fois, d'enregistrer la dernière position d'indice de chaque lettre lors du premier parcours et de diviser la chaîne lors du deuxième parcours.
  • Complexité spatiale : O(∣Σ∣) où Σ est l'ensemble des caractères de la chaîne. Dans cette question, la chaîne ne contient que des lettres minuscules, donc ∣Σ∣=26.

4.1.4. Le meilleur moment pour acheter et vendre des actions II

4.1.4.1, description du sujet

122. Le meilleur moment pour acheter et vendre des actions II

vous donne un tableau de prix entiers, où prices[i]représente le prix d'une certaine action le ijour même.

Chaque jour, vous pouvez décider d’acheter et/ou de vendre des actions. Vous ne pouvez pas détenir plus d’ une action à la fois. Vous pouvez également acheter d'abord, puis vendre le même jour . Renvoyez le profit maximum

que vous pouvez réaliser .

4.1.4.2, exemple d'entrée et de sortie

Exemple 1 :
Entrée : prix = [7, 1, 5, 3, 6, 4]
Sortie : 7
Explication : acheter le jour 2 (cours de l'action = 1), acheter le jour 3 (cours de l'action = 5) Une fois vendu, ce la transaction peut générer un profit = 5 - 1 = 4.
Ensuite, achetez le 4ème jour (cours de l'action = 3) et vendez le 5ème jour (cours de l'action = 6), cette transaction peut faire un profit = 6 - 3 = 3.
Le bénéfice total est de 4 + 3 = 7.

Exemple 2 :
Entrée : prix = [1, 2, 3, 4, 5]
Sortie : 4
Explication : acheter le jour 1 (cours de l'action = 1), acheter le jour 5 (cours de l'action = 5) Vendre, cette transaction peut faire un profit = 5 - 1 = 4.
Le bénéfice total est de 4.

Exemple 3 :
Entrée : prix = [7, 6, 4, 3, 1]
Sortie : 0
Explication : Dans ce cas, la transaction ne peut pas obtenir un profit positif, donc le profit maximum peut être obtenu en ne participant pas à la transaction, et le profit maximum est de 0.

4.1.4.3, solution au problème

Puisqu'il n'y a pas de limite à l'achat d'actions, d'un point de vue gourmand, vous pouvez négocier tous les jours et choisir une fourchette où le profit est supérieur à 0. Cependant, il convient de noter que, contrairement à l'explication de l'exemple, l'algorithme glouton n'est utilisé que pour calculer le profit maximum.Le processus de calcul n'est pas le processus de transaction lui-même.

class Solution {
    
    
    public int maxProfit(int[] prices) {
    
    
        int ans = 0;
        for (int i = 1; i < prices.length; i++) {
    
    
            // 统计利润大于0的区间
            ans += Math.max(0, prices[i] - prices[i - 1]);
        }
        return ans;
    }
}

Analyse de complexité

  • Complexité temporelle : O(n) , où n est la longueur du tableau. Nous n'avons besoin de parcourir le tableau qu'une seule fois.
  • Complexité spatiale : O(1) , ne nécessite qu'un espace constant pour stocker plusieurs variables.

4.2. Difficulté avancée

4.2.1. Reconstruire les files d'attente en fonction de la hauteur

4.2.1.1, description du sujet

406. Reconstruire la file d'attente en fonction de la hauteur

Supposons qu'un groupe de personnes dans un ordre aléatoire se trouve dans une file d'attente et que le tableau peoplereprésente les attributs de certaines personnes dans la file d'attente (pas nécessairement dans l'ordre). Chacun people[i] = [hi, ki]signifie que la taille de la ième personne est hi, et il y a exactement une personne dont kila taille est supérieure ou égale à devant. Veuillez reconstruire et renvoyer la file d'attente représentée par le tableau d'entrée. La file d'attente renvoyée doit être formatée sous forme de tableau , où est l'attribut de la personne dans la file d'attente ( la personne qui se trouve au début de la file d'attente).hi

peoplequeuequeue[j] = [hj, kj]jqueue[0]

4.2.1.2. Exemple d'entrée et de sortie

Exemple 1 :
Entrée : personnes = [ [7, 0], [4, 4], [7, 1], [5, 0], [6, 1], [5, 2] ] Sortie : [ [
5 , 0], [7, 0], [5, 2], [6, 1], [4, 4], [7, 1] ] Explication : La taille de la personne numérotée 0 est 5, et personne n'est plus grand ou
les
mêmes personnes alignées devant lui.
La personne numérotée 1 a une taille de 7, et il n'y a personne qui soit plus grande ou la même devant elle.
La taille de la personne numérotée 2 est de 5, et il y a 2 personnes de taille plus élevée ou de même taille devant elle, c'est-à-dire les personnes numérotées 0 et 1.
La taille de la personne numérotée 3 est 6, et il y a 1 personne qui est plus grande ou de même taille devant lui, c'est-à-dire la personne numérotée 1.
La taille de la personne numérotée 4 est 4, et il y a 4 personnes de taille plus élevée ou de même taille devant elle, c'est-à-dire les personnes numérotées 0, 1, 2 et 3.
La taille de la personne numérotée 5 est 7, et il y a 1 personne qui est plus grande ou de même taille devant lui, c'est-à-dire la personne numérotée 1.
Donc [[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]] est la file d'attente reconstruite.

Exemple 2 :
Entrée : personnes = [ [6, 0], [5, 0], [4, 0], [3, 2], [2, 2], [1, 4] ] Sortie : [ [
4 , 0], [5, 0], [2, 2], [3, 2], [1, 4], [6, 0] ]

4.2.1.3, solution du problème

Triez d'abord en fonction de la taille du petit au grand, du plus grand devant ou du même nombre de personnes du petit au grand, puis parcourez la file d'attente triée, laissez un espace correspondant devant chaque élément et remplissez les conditions de la tige de la question. , vous pouvez Il est très pratique de restaurer la file d'attente d'origine.

class Solution {
    
    
    public int[][] reconstructQueue(int[][] people) {
    
    
        // 按照身高从小到大,前面身高更高或者相同的人数从少到多进行排序
        Arrays.sort(people, new Comparator<int[]>() {
    
    
            @Override
            public int compare(int[] people0, int[] people1) {
    
    
               if (people0[0] != people1[0]) {
    
    
                   return people0[0] - people1[0];
               } else {
    
    
                   return people0[1] - people1[1];
               }
            }
        });
        // 重新构造的队列
        int[][] ans = new int[people.length][];
        
        // 遍历重新排序后的队列
        for (int[] person : people) {
    
    
            // 需重新入队人员的前面身高更高或者相同的人数,为0时则入队
            int index = person[1];
            // 遍历重新构造的队列(未完全完成)
            for (int j = 0; j < ans.length; j++) {
    
    
                if (index == 0) {
    
    
                    if (ans[j] == null) {
    
    
                        ans[j] = person;
                        break;
                    }
                    continue;
                }
                // 确保需入队人员前面身高更高或者相同的人数要求
                if (ans[j] == null || ans[j][0] >= person[0]) {
    
    
                    index--;
                }
            }
        }
        return ans;
    }
}

Analyse de complexité

  • Complexité temporelle : O(n 2 ) , où n est la longueur du tableau de personnes. Nous avons besoin de O(nlogn) temps pour trier, puis de O(n 2 ) temps pour parcourir chaque personne et les mettre dans la file d'attente. Puisque le premier est asymptotiquement plus petit que le second, la complexité temporelle totale est O(n 2 ).
  • Complexité spatiale : O(logn) .

4.2.2. Séquence non décroissante

4.2.2.1, description du sujet

665. Séquence non décroissante

Étant donné que vous avez un ntableau d'entiers d'une longueur de nums, veuillez juger si le tableau peut devenir une séquence non décroissante en modifiant au plus la plupart des éléments. C'est ainsi que nous définissons un tableau non décroissant : pour tout élément du tableau , il est toujours satisfait .1

i (0 <= i <= n-2)nums[i] <= nums[i + 1]

4.2.2.2. Exemple d'entrée et de sortie

Exemple 1 :
Entrée : nums = [4, 2, 3]
Sortie : true
Explication : Vous pouvez en faire une séquence non décroissante en changeant les 4 premiers en 1.

Exemple 2 :
Entrée : nums = [4, 2, 1]
Sortie : false
Explication : Vous ne pouvez pas en faire une séquence non décroissante en modifiant un seul élément.

4.2.2.3, solution du problème

En partant du principe qu'au plus un élément est modifié, si le tableau est transformé en une séquence non décroissante, il vous suffit de parcourir le tableau, de le modifier et de le compter lorsque vous rencontrez une condition non décroissante, et d'échouer lorsque le deuxième changement se produit.


Pendant le parcours, lorsque l'élément suivant est plus petit que le précédent, s'il s'agit du début ou de la fin du tableau, il n'est pas nécessaire de changer le tableau, il suffit de compter, car cela peut être considéré comme définissant le premier élément du tableau à la valeur minimale, ou définir le tableau. En fin de compte, je pensais qu'il était défini sur la valeur maximale et qu'il ne serait pas utilisé plus tard, il n'est donc pas nécessaire de le modifier.


S'il se trouve au milieu du tableau, il existe en fait deux méthodes de traitement à ce stade, l'une consiste à modifier la valeur pour qu'elle soit identique à la valeur précédente et l'autre consiste à modifier la valeur précédente pour qu'elle soit identique à la valeur précédente. valeur (ici, il faut s'assurer qu'après avoir modifié la valeur précédente, cela n'affectera pas sa condition non décroissante), ici nous devons d'abord utiliser la deuxième méthode, car cette valeur doit être comparée aux valeurs suivantes, elle devrait donc veillez à ce que la valeur soit la plus petite possible.

class Solution {
    
    
    public boolean checkPossibility(int[] nums) {
    
    
        for (int i = 1, count = 0; i < nums.length; i++) {
    
    
            if (nums[i] < nums[i - 1]) {
    
    
                if (i != 1 && i != nums.length - 1 && nums[i] < nums[i - 2]) {
    
    
                    nums[i] = nums[i - 1];
                }
                if (++count > 1) {
    
    
                    return false;
                }
            }
        }
        return true;
    }
}

Analyse de complexité

  • Complexité temporelle : O(n) , où n est la longueur des nombres du tableau.
  • Complexité spatiale : O(1) .

Je suppose que tu aimes

Origine blog.csdn.net/rockvine/article/details/125472114
conseillé
Classement