491, la solution d'algorithme de retour arrière divise le tableau en séquences de Fibonacci

Insérez la description de l'image ici

Si vous souhaitez voir plus de questions d'algorithme, vous pouvez scanner le code QR ci-dessus et suivre mon compte officiel WeChat " Structure de données et algorithme ". Jusqu'à présent, j'ai mis à jour plus de 500 questions d'algorithme dans le compte officiel , dont certaines ont été triés en documents pdf., À partir de maintenant, il y a plus de 800 pages au total (et continuera d'augmenter), vous pouvez répondre au mot-clé "pdf" dans le compte officiel pour télécharger.


Description du problème

Étant donné une chaîne de nombres S, telle que S = "123456579" , nous pouvons la diviser en séquences de type Fibonacci [123, 456, 579].


Formellement, la séquence de Fibonacci est une liste F d'entiers non négatifs et satisfait:

  • 0 <= F [i] <= 2 ^ 31-1, (c'est-à-dire que chaque entier est conforme au type entier signé 32 bits);
  • F.longueur> = 3 ;
  • Pour tout 0 <= i <F.length-2, F [i] + F [i + 1] = F [i + 2] est valable.

De plus, veuillez noter que lors de la division de la chaîne en petits blocs, le numéro de chaque bloc ne doit pas commencer par un zéro, sauf si le bloc est le numéro 0 lui-même.


Renvoie tout ensemble de blocs de séquence de type Fibonacci séparés de S, ou [] s'il ne peut pas être divisé.


Exemple 1:

Entrée : "123456579"

Sortie : [123 456 579]

Exemple 2:

Entrée : "11235813"

Sortie : [1,1,2,3,5,8,13]

Exemple 3:

Entrée : "112358130"

Sortie : []

Explication : Cette tâche ne peut pas être terminée.

Exemple 4:

Entrée : "0123"

Sortie : []

Explication : Le numéro de chaque bloc ne peut pas commencer par zéro, donc "01", "2" et "3" ne sont pas des réponses valides.

Exemple 5:

Entrée : "1101111"

Sortie : [110, 1, 111]

Explication : La sortie [11,0,11,11] est également acceptée.


rapide:

  • 1 <= longueur S. <= 200
  • La chaîne S ne contient que des nombres.

Solution d'algorithme de backtracking

Cette question est de diviser la chaîne S en quelques sous-chaînes, et ces sous-chaînes satisfont la relation de la séquence de Fibonacci. Pour ce problème, nous pouvons utiliser l'algorithme de retour arrière pour le résoudre. L' algorithme de retour arrière est en fait un processus de tentatives continues . Une fois la tentative réussie, elle réussira. Si la tentative échoue, elle reviendra à l'étape précédente. Remarque que lorsque vous revenez à l'étape précédente, vous restaurerez l'état à l'état de l'étape précédente. L'algorithme de retour arrière ne sera pas trop introduit ici. Pour les idées de résolution de problème de l'algorithme de retour arrière, vous pouvez voir 450. Qu'est-ce qu'un algorithme de retour arrière? Vous pouvez le lire au premier coup d'œil, et il sera inutile lorsque vous l'écrivez .


L'algorithme de retour arrière a en fait un modèle classique

private void backtrack("原始参数") {
    
    
    //终止条件(递归必须要有终止条件)
    if ("终止条件") {
    
    
        //一些逻辑操作(可有可无,视情况而定)
        return;
    }

    for (int i = "for循环开始的参数"; i < "for循环结束的参数"; i++) {
    
    
        //一些逻辑操作(可有可无,视情况而定)

        //做出选择

        //递归
        backtrack("新的参数");
        //一些逻辑操作(可有可无,视情况而定)

        //撤销选择
    }
}

Il en va de même pour cette question. Interceptons d'abord continuellement la chaîne pour voir si elle peut former une séquence de Fibonacci. Si ce n'est pas le cas, revenez à l'étape précédente. Si c'est le cas, continuez à descendre. Pour plus de détails, nous allons Regardez la figure ci-dessous., Voici une image dessinée en référence à l'exemple 1, mais le nombre est raccourci, seulement 124557, car s'il y a plus de nombres, l'image est trop grande pour être dessinée.

Insérez la description de l'image ici

Comprenez les principes ci-dessus, le code est beaucoup plus simple, jetons un œil au code

public List<Integer> splitIntoFibonacci(String S) {
    
    
    List<Integer> res = new ArrayList<>();
    backtrack(S.toCharArray(), res, 0);
    return res;
}

public boolean backtrack(char[] digit, List<Integer> res, int index) {
    
    
    //边界条件判断,如果截取完了,并且res长度大于等于3,表示找到了一个组合。
    if (index == digit.length && res.size() >= 3) {
    
    
        return true;
    }
    for (int i = index; i < digit.length; i++) {
    
    
        //两位以上的数字不能以0开头
        if (digit[index] == '0' && i > index) {
    
    
            break;
        }
        //截取字符串转化为数字
        long num = subDigit(digit, index, i + 1);
        //如果截取的数字大于int的最大值,则终止截取
        if (num > Integer.MAX_VALUE) {
    
    
            break;
        }
        int size = res.size();
        //如果截取的数字大于res中前两个数字的和,说明这次截取的太大,直接终止,因为后面越截取越大
        if (size >= 2 && num > res.get(size - 1) + res.get(size - 2)) {
    
    
            break;
        }
        if (size <= 1 || num == res.get(size - 1) + res.get(size - 2)) {
    
    
            //把数字num添加到集合res中
            res.add((int) num);
            //如果找到了就直接返回
            if (backtrack(digit, res, i + 1))
                return true;
            //如果没找到,就会走回溯这一步,然后把上一步添加到集合res中的数字给移除掉
            res.remove(res.size() - 1);
        }
    }
    return false;
}

//相当于截取字符串S中的子串然后转换为十进制数字
private long subDigit(char[] digit, int start, int end) {
    
    
    long res = 0;
    for (int i = start; i < end; i++) {
    
    
        res = res * 10 + digit[i] - '0';
    }
    return res;
}

Pour résumer

Il n'y a pas beaucoup de types de questions algorithmiques qui ont vraiment des modèles, mais l'algorithme de retour en arrière en fait partie. C'est simplement que différents types de questions doivent être modifiés différemment. Tant que vous maîtrisez ce modèle, vous pouvez modifier légèrement de nombreux algorithmes de retour en arrière. types de questions. C'est facile à faire.

Je suppose que tu aimes

Origine blog.csdn.net/abcdef314159/article/details/112498301
conseillé
Classement