Jour 2 | 209. Sous-tableau de longueur minimale

Référence :
Code Caprice [Sous-tableau avec la plus petite longueur]

zéro, descriptif

Étant donné un tableau de n entiers positifs et une cible de tableau positif.

Exemple :
Entrée : cible = 7, nums = [2,3,1,2,4,3]
Sortie : 2
Explication : Le sous-tableau [4,3] est le sous-tableau avec la plus petite longueur sous cette condition.

Entrée : cible = 4, nombres = [1,4,4]
Sortie : 1

Entrée : cible = 11, nombres = [1,1,1,1,1,1,1,1]
Sortie : 0

1. Solution : solution violente

Deux boucles for, puis continuez à chercher des sous-séquences qualifiées,
complexité temporelle : O ( n 2 ) O(n^2)O ( n2 )

code:

class Solution {
    
    
public:
    int minSubArrayLen(int s, vector<int>& nums) {
    
    
        int result = INT32_MAX; // 最终的结果
        int sum = 0;            // 子序列的数值之和
        int subLength = 0;      // 子序列的长度
        for (int i = 0; i < nums.size(); i++) {
    
     
        // 设置子序列起点为i
            sum = 0;
            for (int j = i; j < nums.size(); j++) {
    
     
            // 设置子序列终止位置为j
                sum += nums[j];
                if (sum >= s) {
    
     
                // 一旦发现子序列和超过了s,更新result
                    subLength = j - i + 1; 
                    // 取子序列的长度
                    result = result < subLength ? result : subLength;
                    break; 
                    // 因为我们是找符合条件最短的子序列,所以一旦符合条件就break
                }
            }
        }
        // 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
        return result == INT32_MAX ? 0 : result;
    }
};

2. Solution : fenêtre coulissante

Fenêtre glissante : l'essentiel est toujours que le double pointeur
ajuste constamment la position de départ et la position de fin de la sous-séquence, de manière à obtenir le résultat que nous voulons ; dans la solution violente, c'est la position de départ d'une fenêtre glissante de boucle for , et une boucle for En tant que position finale de la fenêtre glissante, deux boucles for sont utilisées pour terminer un processus de recherche continue de l'intervalle.

Si une boucle for est utilisée, doit-elle indiquer la position de départ de la fenêtre glissante ou la position de fin ?

  • Une seule boucle for est utilisée pour représenter la position de départ de la fenêtre glissante , alors comment parcourir les positions de fin restantes ?
  • Donc une seule boucle for est utilisée, alors l'index de cette boucle doit indiquer la position finale de la fenêtre glissante
    Position finale : la fenêtre est le sous-tableau continu avec la plus petite longueur satisfaisant sa somme ≥ cible

L'essentiel:

  • Trouvez d'abord un sous-tableau continu depuis le début dont la somme est supérieure à la cible, la fonction est de fixer le bon pointeur
  • À ce moment, commencez à déplacer le pointeur gauche et le pointeur gauche se déplace. Lorsque la somme des sous-tableaux continus est inférieure à la cible, le pointeur gauche est fixe
  • Déplacez ensuite le pointeur droit de sorte que le sous-réseau continu soit plus grand que la cible, et fixez le pointeur droit
  • Parcourez les étapes ci-dessus

la complexité:

  • Complexité temporelle : O(n^2) solution de force brute est réduite à O(n).
    Ne pensez pas que mettre un moment dans le for est O(n^2). Cela
    dépend principalement du nombre de fois que chaque élément est Après la fenêtre glissante, l'opération entre une fois et l'opération s'éteint une fois. Chaque élément est opéré deux fois, de sorte que la complexité temporelle est de 2 × n, qui est O (n).
  • Complexité spatiale : O(1)

insérez la description de l'image ici

code:

class Solution {
    
    
public:
    int minSubArrayLen(int target, vector<int>& nums) {
    
    
        int result = INT32_MAX;	//给一个很大的值
        int sum = 0; 			// 滑动窗口数值之和
        int i = 0;   			// 滑动窗口起始位置
        int subLength = 0; 		// 滑动窗口的长度
        
        // j 指的是终止位置
        for (int j = 0; j < nums.size(); j++) {
    
    
            sum += nums[j];
        	// 注意这里使用while,每次更新 i(起始位置),并不断比较子序列是否符合条件
		
        	// 1.先找到前j项和大于等于target的j
            while ( sum >= target ) {
    
     
                subLength = (j - i + 1); 					      // 取子序列的长度
                result = result < subLength ? result : subLength; //result表示当前的最短长度
                sum -= nums[i++]; 						// 这里体现出滑动窗口的精髓之处,不断变更i(子序列的起始位置)
            }
        }
        // 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
        return result == INT32_MAX ? 0 : result;
    }
};

3. Résumé

On peut penser à des doubles pointeurs, mais ils tombent toujours dans le cercle des solutions violentes.
La clé est de penser que ce qui est fixé en premier n'est pas le point de départ (ou appelé le pointeur gauche), mais le point final (le pointeur droit).
Essayez d'abord de monter les marches avec votre pied droit. Après avoir fixé le pied droit, déplacez le pied gauche.
Après avoir déplacé le pied gauche, si les conditions ne sont pas remplies, déplacez à nouveau le pied droit.

Je suppose que tu aimes

Origine blog.csdn.net/weifengomg/article/details/128237778
conseillé
Classement