Jour 12 de la revue des algorithmes : programmation dynamique

Table des matières

Un, monte les escaliers

 1. Programmation dynamique

2. Exponentiation rapide matricielle

3, fonctionnaire Tongyu

Résumer

2. Vol et vol

1. Programmation dynamique

Analyse de complexité

3. Somme minimale du chemin du triangle

Voir la solution :

Un, monte les escaliers

70. Monter les escaliers - LeetCode https://leetcode.cn/problems/climbing-stairs/?plan=algorithms&plan_progress=gzwnnxs

 1. Programmation dynamique

class Solution {
public:
    int climbStairs(int n) {
        int p = 0, q = 0, r = 1;
        for (int i = 1; i <= n; ++i) {
            p = q; 
            q = r; 
            r = p + q;
        }
        return r;
    }
};

2. Exponentiation rapide matricielle

class Solution {
public:
    vector<vector<long long>> multiply(vector<vector<long long>> &a, vector<vector<long long>> &b) {
        vector<vector<long long>> c(2, vector<long long>(2));
        for (int i = 0; i < 2; i++) {
            for (int j = 0; j < 2; j++) {
                c[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j];
            }
        }
        return c;
    }

    vector<vector<long long>> matrixPow(vector<vector<long long>> a, int n) {
        vector<vector<long long>> ret = {
   
   {1, 0}, {0, 1}};
        while (n > 0) {
            if ((n & 1) == 1) {
                ret = multiply(ret, a);
            }
            n >>= 1;
            a = multiply(a, a);
        }
        return ret;
    }

    int climbStairs(int n) {
        vector<vector<long long>> ret = {
   
   {1, 1}, {1, 0}};
        vector<vector<long long>> res = matrixPow(ret, n);
        return res[0][0];
    }
};

3, fonctionnaire Tongyu

class Solution {
public:
    int climbStairs(int n) {
        double sqrt5 = sqrt(5);
        double fibn = pow((1 + sqrt5) / 2, n + 1) - pow((1 - sqrt5) / 2, n + 1);
        return (int)round(fibn / sqrt5);
    }
};

Résumer


La séquence formée ici se trouve être la séquence de Fibonacci, et le f(n)f(n) requis par la réponse est le nième élément de la séquence de Fibonacci (l'indice commence à 0). Résumons la solution du nième terme de la séquence de Fibonacci :

Lorsque n est relativement petit, la méthode récursive peut être utilisée directement pour résoudre le problème sans aucune opération de mémorisation. La complexité temporelle est O(2^n) et il existe de nombreux calculs redondants.
Dans des circonstances normales, nous utilisons des méthodes de « recherche en mémoire » ou « d'itération » pour implémenter cette équation de transfert, et la complexité temporelle et la complexité spatiale peuvent être O(n).
Afin d'optimiser la complexité spatiale, nous n'avons pas besoin de sauvegarder les éléments avant f(x−2). Nous n'utilisons que trois variables pour maintenir f(x), f(x−1) et f(x−2) Vous pouvez comprendre que Cheng applique « l'idée du tableau roulant » à la programmation dynamique, qui peut également être comprise comme une sorte de récursion, optimisant ainsi la complexité spatiale à O(1).
À mesure que n continue d'augmenter, O(n) peut ne plus répondre à nos besoins. Nous pouvons utiliser la méthode "d'exponentiation rapide matricielle" pour accélérer l'algorithme jusqu'à O(logn).
Nous pouvons également substituer n dans la formule générale de la séquence de Fibonacci pour calculer le résultat, mais si nous utilisons des calculs en virgule flottante pour l'implémenter, des erreurs de précision peuvent survenir.

2. Vol et vol

198. Voleur de maison - LeetCode https://leetcode.cn/problems/house-robber/?plan=algorithms&plan_progress=gzwnnxs

1. Programmation dynamique


Considérons d’abord le cas le plus simple. S'il n'y a qu'une seule maison, volez-la jusqu'au montant total maximum que vous pouvez voler. S'il n'y a que deux maisons, puisque les deux maisons sont adjacentes, vous ne pouvez pas voler en même temps, vous ne pouvez voler qu'une des maisons, donc choisissez la maison avec le montant le plus élevé à voler, et vous pourrez voler jusqu'au total maximum. montant.

S’il y a plus de deux maisons, comment calculer le montant total maximum pouvant être volé ? Pour la kème (k>2) maison, il y a deux options :

Si vous volez la k-ème maison, vous ne pouvez pas voler la k-ème maison. Le montant total volé est la somme du montant total le plus élevé des premières k-2 maisons et du montant de la k-ème maison.

Sans voler la k-ème maison, le montant total volé est le montant total le plus élevé des k-1 premières maisons.

Choisissez l'option avec un montant total de vol plus élevé parmi les deux options. Le montant total du vol correspondant à cette option est le montant total maximum d'argent pouvant être volé dans les k premières maisons.

Soit dp[i] représente le montant total maximum qui peut être volé dans les i premières maisons, alors il existe l'équation de transition d'état suivante :


dp[i]=max(dp[i−2]+nums[i],dp[i−1])

Les conditions aux limites sont :


dp[0]=nums[0] Il n'y a qu'une seule maison, alors volez la maison
dp[1]=max(nums[0],nums[1]) Il n'y a que deux maisons, choisissez la maison avec le montant le plus élevé pour
voler
 

La réponse finale est dp[n−1], où n est la longueur du tableau.

class Solution {
public:
    int rob(vector<int>& nums) {
        if (nums.empty()) {
            return 0;
        }
        int size = nums.size();
        if (size == 1) {
            return nums[0];
        }
        vector<int> dp = vector<int>(size, 0);
        dp[0] = nums[0];
        dp[1] = max(nums[0], nums[1]);
        for (int i = 2; i < size; i++) {
            dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);
        }
        return dp[size - 1];
    }
};

La méthode ci-dessus utilise un tableau pour stocker les résultats. Étant donné que le montant total maximum de chaque maison n'est lié qu'au montant total maximum des deux premières maisons de la maison, un réseau roulant peut être utilisé pour stocker uniquement le montant total maximum des deux premières maisons à chaque instant.

class Solution {
public:
    int rob(vector<int>& nums) {
        if (nums.empty()) {
            return 0;
        }
        int size = nums.size();
        if (size == 1) {
            return nums[0];
        }
        int first = nums[0], second = max(nums[0], nums[1]);
        for (int i = 2; i < size; i++) {
            int temp = second;
            second = max(first + nums[i], second);
            first = temp;
        }
        return second;
    }
};

Analyse de complexité

Complexité temporelle : O(n), où n est la longueur du tableau. Le tableau ne doit être parcouru qu’une seule fois.

Complexité spatiale : O(1). En utilisant un tableau déroulant, vous pouvez stocker uniquement le montant total le plus élevé des deux premières maisons sans stocker les résultats de l'ensemble du tableau, la complexité spatiale est donc O(1).

3. Somme minimale du chemin du triangle

120. Somme minimale du chemin des triangles - LeetCode https://leetcode.cn/problems/triangle/?plan=algorithms&plan_progress=gzwnnxs

Cette question est une question de programmation dynamique très classique et ancienne. Elle est apparue comme une question d'algorithme et remonte au Triangle de l'IOI (Olympiade Internationale d'Informatique) en 1994. Le temps passe vite. Après plus de 20 ans d'accumulation, les questions de compétition internationale passées sont désormais devenues des questions incontournables pour la programmation dynamique d'entrée de gamme, nous poussant constamment à apprendre et à consolider les algorithmes.

Dans ce problème, le nombre de lignes du triangle donné est n et la i-ème ligne (numérotée à partir de 00) contient i+1 nombres. Si vous alignez les extrémités gauches de chaque rangée, cela formera un triangle rectangle isocèle, comme indiqué ci-dessous :

[2]
[3,4]
[6,5,7]
[4,1,8,3]

Voir la solution :

Somme minimale du chemin des triangles - Somme minimale du chemin des triangles - LeetCode https://leetcode.cn/problems/triangle/solution/san-jiao-xing-zui-xiao-lu-jing-he-by-leetcode-solu /

Je suppose que tu aimes

Origine blog.csdn.net/m0_63309778/article/details/126755316
conseillé
Classement