Algorithme glouton: nombres monotones croissants

Changé pour un nouveau thème de typographie, haha, comment vous sentez-vous?

Remarque: certains amis enregistreurs ont déclaré qu'ils ne voyaient souvent pas d'articles tous les jours. Désormais, le compte officiel ne les recommande plus en fonction de l'heure d'envoi, mais les met dans le désordre conformément à certaines règles. Il est recommandé de mettre une étoile pour "Code Caprice". Après avoir fixé l'étoile, elle sera repoussée en fonction de l'heure d'affichage tous les jours. Carl l'envoie régulièrement à 8h35 tous les jours, oh ponctuel!

738. Nombres monotones croissants
Étant donné un entier non négatif N, trouvez le plus grand entier inférieur ou égal à N, et cet entier doit vérifier que les nombres sur chaque chiffre augmentent de façon monotone.

(Si et seulement si les nombres x et y de chaque chiffre adjacent satisfont x <= y, nous appelons cet entier croissant monotone.)

Exemple 1:
Entrée: N = 10
Sortie: 9

Exemple 2:
Entrée: N = 1234
Sortie: 1234

Exemple 3:
Entrée: N = 332
Sortie: 299

Explication: N est un entier compris entre [0, 10 ^ 9].

L'idée de
solution violente
est très simple, donc la première chose à laquelle il faut penser est une solution violente. Permettez-moi de mentionner une vague de violence. Le résultat est naturellement des heures supplémentaires!

code montrer comme ci-dessous:


class Solution {
private:
    bool checkNum(int num) {
        int max = 10;
        while (num) {
            int t = num % 10;
            if (max >= t) max = t;
            else return false;
            num = num / 10;
        }
        return true;
    }
public:
    int monotoneIncreasingDigits(int N) {
        for (int i = N; i > 0; i--) {
            if (checkNum(i)) return i;
        }
        return 0;
    }
};
  • Complexité temporelle: O (n * m) m est la longueur numérique de n
  • Complexité spatiale: O (1) Le problème d'
    algorithme glouton
    nécessite le plus grand nombre entier croissant monotone inférieur ou égal à N, prenez donc un nombre à deux chiffres comme exemple.

Par exemple: 98, une fois que strNum [i-1]> strNum [i] se produit (sans augmentation monotone), je veux d'abord strNum [i-1] -, puis strNum [i] vaut 9, de sorte que cet entier est 89, qui est le plus grand entier monotone croissant inférieur à 98.

Si vous y réfléchissez clairement, cette question sera plus facile à traiter.

Local optimal: dans le cas de strNum [i-1]> strNum [i], soit strNum [i-1] -, puis strNum [i] à 9 pour s'assurer que ces deux bits deviennent le plus grand entier monotone croissant .

Optimale globale: obtenir le plus grand entier croissant monotone inférieur ou égal à N.

Mais ici, l'optimum local est dérivé de l'optimum global, et d'autres conditions sont nécessaires, c'est-à-dire l'ordre de parcours et la marque à partir de laquelle le bit est changé en 9.

Est-ce pour traverser d'avant en arrière ou d'arrière en avant?

Si vous traversez d'avant en arrière, si strNum [i-1]> strNum [i] est rencontré, laissez strNum [i-1] soustraire un, mais si strNum [i-1] est soustrait par un, il peut être inférieur à strNum [i-2].

C'est un peu abstrait, par exemple, le nombre: 332, si vous traversez d'avant en arrière, alors il devient 329. À ce stade, 2 est plus petit que les 3 premiers, et le résultat réel devrait être 299.

Donc, parcourir d'avant en arrière changera les résultats qui ont été parcourus!

Ensuite, de l'arrière vers l'avant, vous pouvez réutiliser le résultat de la dernière comparaison. La valeur de 332 de l'arrière vers l'avant passe à: 332 -> 329 -> 299

Après avoir déterminé la séquence de parcours, alors l'optimal local peut être dérivé du global à ce moment, et si aucun contre-exemple ne peut être trouvé, essayez d'être gourmand.

Le code C ++ est le suivant:


class Solution {
public:
    int monotoneIncreasingDigits(int N) {
        string strNum = to_string(N);
        // flag用来标记赋值9从哪里开始
        // 设置为这个默认值,为了防止第二个for循环在flag没有被赋值的情况下执行
        int flag = strNum.size();
        for (int i = strNum.size() - 1; i > 0; i--) {
            if (strNum[i - 1] > strNum[i] ) {
                flag = i;
                strNum[i - 1]--;
            }
        }
        for (int i = flag; i < strNum.size(); i++) {
            strNum[i] = '9';
        }
        return stoi(strNum);
    }
};
  • Complexité temporelle: O (n) n est la longueur du nombre
  • Complexité de l'espace: O (n) nécessite une chaîne, et il est plus pratique de la convertir en une opération de chaîne.
    Pour résumer
    cette question, pensez à un exemple clair, tel que 98. Une fois que strNum [i-1]> strNum [i] se produit (sans augmentation monotone) ), je veux d'abord soustraire un de strNum [i-1] et attribuer 9 à strNum [i], de sorte que l'entier soit 89. Vous pouvez naturellement penser à la solution gourmande correspondante.

En pensant à la cupidité, il faut aussi considérer l'ordre de traversée: c'est seulement en parcourant de l'arrière vers l'avant que les résultats de la dernière comparaison peuvent être réutilisés.

Lorsque le code final est implémenté, certaines compétences sont également nécessaires, comme l'utilisation d'un drapeau pour marquer où commencer l'attribution de 9.

Apprenez simplement l'algorithme étape par étape et recherchez "Code Random Record"!

Je suppose que tu aimes

Origine blog.51cto.com/15069438/2576225
conseillé
Classement