Analyse des idées de résolution de problèmes Leetcode (37) 307-316

  1. La zone et le tableau de récupération peuvent être modifiés

Une question très simple

class NumArray {
    
    
        vector<int> m_sum;
        vector<int> m_nums;
public:
    NumArray(vector<int>& nums) {
    
    
        m_nums = nums;
        m_sum = nums;

        if (nums.size() == 0) 
            return;

        for (int i = 1; i < nums.size(); i++)
        {
    
    
            m_sum[i] += m_sum[i - 1];
        }
    }
    
    void update(int i, int val) {
    
    
        int dif = val - m_nums[i];
        m_nums[i] = val;

        for (int j = i; j < m_sum.size(); j++)
        {
    
    
            m_sum[j] += dif;
        }
    }
    
    int sumRange(int i, int j) {
    
    
        if (i == 0)
            return m_sum[j];
        else
            return m_sum[j] - m_sum[i - 1];
    }
};

/**
 * Your NumArray object will be instantiated and called as such:
 * NumArray* obj = new NumArray(nums);
 * obj->update(i,val);
 * int param_2 = obj->sumRange(i,j);
 */
  1. Le meilleur moment pour acheter et vendre des actions comprend la période de gel.
    Étant donné un tableau d'entiers, le i-ème élément représente le cours de l'action le i-ème jour.
    Concevez un algorithme pour calculer le profit maximum. Sous les contraintes suivantes, vous pouvez effectuer autant de transactions que possible (acheter et vendre une action plusieurs fois):
    Vous ne pouvez pas participer à plusieurs transactions en même temps (vous devez vendre l'action précédente avant d'acheter à nouveau).
    Après avoir vendu le stock, vous ne pouvez pas acheter le stock le lendemain (c'est-à-dire que la période de congélation est de 1 jour)

Application de programmation dynamique classique. Notez d'abord la relation entre l'état le jour I et le jour i-1, puis effectuez une optimisation de la réduction de dimensionnalité.

class Solution {
    
    
public:
    int maxProfit(vector<int>& prices) {
    
    
        if (prices.empty()) {
    
    
            return 0;
        }

        int n = prices.size();
        int f0 = -prices[0];
        int f1 = 0;
        int f2 = 0;
        for (int i = 1; i < n; ++i) {
    
    
            int newf0 = max(f0, f2 - prices[i]);
            int newf1 = f0 + prices[i];
            int newf2 = max(f1, f2);
            f0 = newf0;
            f1 = newf1;
            f2 = newf2;
        }

        return max(f1, f2);
    }
};
  1. Arbre de hauteur minimale
    Pour un graphe non orienté avec des caractéristiques d'arbre, nous pouvons choisir n'importe quel nœud comme racine. Les graphes peuvent donc devenir des arbres: parmi tous les arbres possibles, l'arbre avec la plus petite hauteur est appelé l'arbre le plus petit. Étant donné un tel graphe, écrivez une fonction pour trouver tous les arbres de hauteur minimale et renvoyer leurs nœuds racines.

Le point principal de cette question est que si l'arbre de hauteur minimale utilise la feuille du graphique comme racine, les autres points vers la feuille sont au moins 1 + nœud parent feuille. On peut voir que les nœuds feuilles ne sont pas notre option. Rapprochez-vous du milieu de tous les nœuds feuilles et pelez-les de manière récursive couche par couche jusqu'à ce qu'ils se rencontrent, ce qui correspond à l'intersection avec la distance la plus courte. Selon la profondeur, le nombre pair et impair peut être 1 résultat ou 2 résultats

class Solution {
    
    
public:
vector<int> findMinHeightTrees(int n, vector<vector<int>>& edges) {
    
    
	if (n == 1)
		return {
    
     0 };
	else if (n == 2)
		return{
    
     0,1 };

	vector<int> indegree(n,0);//入度数组,并初始化
	vector<int> v;
	vector<vector<int>> graph(n,v);//图形表示,并初始化
	for (int i = 0; i < edges.size(); i++)//构造图与入度数组:无向图,两个点都要处理
	{
    
    
		graph[edges[i][0]].push_back(edges[i][1]);
		graph[edges[i][1]].push_back(edges[i][0]);
		indegree[edges[i][0]]++;
		indegree[edges[i][1]]++;
	}
	queue<int> myqueue;//装载入度为1的queue
	for (int i = 0; i < n; i++)
	{
    
    
		if (indegree[i] == 1)
			myqueue.push(i);
	}
	int cnt = myqueue.size();//!!令cnt等于myqueue.size(),一次性将入度为1的点全部删去。
	while (n>2)
	{
    
    
		n -= cnt;//一次性将入度为一的点全部删去!!不能一个一个删!
		while (cnt--)
		{
    
    
			int temp = myqueue.front();
			myqueue.pop();
			indegree[temp] = 0;
			//更新temp的邻接点:若temp临接点的入度为1,则将其放入queue中。
			for (int i = 0; i < graph[temp].size(); i++)
			{
    
    
				if (indegree[graph[temp][i]] != 0)
				{
    
    
					indegree[graph[temp][i]]--;
					if (indegree[graph[temp][i]] == 1)//放在这里做!只判断邻接点。
						myqueue.push(graph[temp][i]);
				}
				
			}
		}
		cnt = myqueue.size();
	}
	vector<int> result;
	while (!myqueue.empty())
	{
    
    
		result.push_back(myqueue.front());
		myqueue.pop();
	}
	return result;
}
};

  1. Poke balloons
    Il y a n ballons, numérotés de 0 à n-1. Chaque bulle est marquée d'un nombre, et ces nombres sont stockés dans le tableau nums.

Vous devez maintenant faire éclater tous les ballons. Si vous faites éclater le ballon i, vous pouvez obtenir des pièces nums [gauche] * nums [i] * nums [droite]. Ici, gauche et droite représentent les numéros de série des deux ballons adjacents à i. Notez que lorsque vous éclatez le ballon i, les ballons gauche et droit deviennent des ballons adjacents.
Trouvez le nombre maximum de pièces pouvant être obtenues.

Les problèmes de programmation dynamique classique peuvent être résolus par une réflexion descendante ou ascendante. Idée principale: s'il s'agit de piquer un ballon, piquez d'abord le plus petit ballon intérieur et piquez le bord en dernier. Si vous ajoutez des ballons, ajoutez-les à partir du plus grand

class Solution {
    
    
public:
    int maxCoins(vector<int>& nums) {
    
    
        int n = nums.size();
        vector<vector<int>> rec(n + 2, vector<int>(n + 2));
        vector<int> val(n + 2);
        val[0] = val[n + 1] = 1;
        for (int i = 1; i <= n; i++) {
    
    
            val[i] = nums[i - 1];
        }
        for (int i = n - 1; i >= 0; i--) {
    
    
            for (int j = i + 2; j <= n + 1; j++) {
    
    
                for (int k = i + 1; k < j; k++) {
    
    
                    int sum = val[i] * val[k] * val[j];
                    sum += rec[i][k] + rec[k][j];
                    rec[i][j] = max(rec[i][j], sum);
                }
            }
        }
        return rec[0][n + 1];
    }
};


  1. Nombre super laid
    Ecrivez un programme pour trouver le nième nombre super laid.
    Un nombre super laid signifie que tous les facteurs premiers sont des entiers positifs en nombres premiers, une liste de nombres premiers de longueur k.

1) La source des éléments de la file d'attente: élément supérieur * liste des nombres premiers, placez les éléments nouvellement générés dans la file d'attente, et le nième élément qui apparaît est le nombre super laid que nous voulons. Cependant, l'élément popped n'est pas nécessairement le n-ième plus petit nombre premier, nous devons donc le trier avant de sauter.
2) Pour le nième nombre premier, la file d'attente doit être ordonnée et organisée du petit au grand, nous prenons donc la petite pile du haut

class Solution {
    
    
public:
    int nthSuperUglyNumber(int n, vector<int> &primes)
    {
    
    
        priority_queue<long long, vector<long long>, greater<long long>> buff;
        unordered_set<long long> primeset;

        buff.push(1);
        primeset.insert(1);
        long long i = 1;
        int count = 0;
        while (count < n) {
    
    
            count++;
            i = buff.top();
            buff.pop();
            for (long long prime : primes) {
    
    
                long long next = i * prime;
                if (next<=INT32_MAX && !primeset.count(next)) {
    
    
                    buff.push(next);
                    primeset.insert(next);
                }
            }
        }

        return i;
    }
};

  1. Calculez le nombre d'éléments sur le côté droit qui sont inférieurs à l'élément actuel.
    Étant donné un tableau d'entiers nums, renvoie un nouveau tableau compte comme requis. Le tableau count a cette propriété: la valeur de count [i] est le nombre d'éléments sur le côté droit de nums [i] qui sont inférieurs à nums [i].

Ce problème est résolu par un tableau d'arbres, qui est un problème classique. On comprend que chaque compartiment stocke un certain nombre de valeurs, puis peut être accumulé

class Solution {
    
    
private:
    int lowbit(int x){
    
    
        return x & (-x);
    }
    void update(int i, vector<int>&C){
    
    
        while (i < C.size()) {
    
    
            C[i]++;
            i += lowbit(i);
        }
    }
    void query(int i, int j, vector<int>&C, vector<int>&counts){
    
    
        while (i >= 1) {
    
    
            counts[j] += C[i];
            i -= lowbit(i);
        }
    }
public:    
    vector<int> countSmaller(vector<int>& nums) {
    
    
        vector<int>counts(nums.size(), 0);
        if (nums.size() < 1) {
    
    
            return counts;
        }
        
        vector<int>N(nums);
        // Sort and unique
        sort(N.begin(), N.end());
        int slow = 1;
        int fast = 1;
        while(fast< N.size()) {
    
    
            if (N[fast] != N[slow - 1]) {
    
    
                N[slow] = N[fast];
                slow++;
                fast++;
            }else{
    
    
                fast++;
            }
        }
        N.resize(slow);
        
        // key: number, value: i
        map<int, int>m;
        for (int j = 1; j < 1 + N.size(); ++j) {
    
    
            m[N[j - 1]] = j;
        }
        
        // traverse
        vector<int>C(N.size() + 1, 0); //  C[i] is necessary, but A[i] not
        int i;
        for (int j = nums.size() - 1; j >= 0; --j) {
    
    
            i = m[nums[j]];
            update(i, C);
            if (i != 1) {
    
    
                query(i - 1, j, C, counts);
            }else{
    
    
                counts[j] = 0;
            }
        }
        return counts;
    }
};

  1. Supprimer les lettres répétées
    Vous donne une chaîne contenant uniquement des lettres minuscules. Veuillez supprimer les lettres répétées de la chaîne afin que chaque lettre n'apparaisse qu'une seule fois. Il faut s'assurer que l'ordre lexicographique du résultat renvoyé est le plus petit (nécessaire pour ne pas perturber la position relative des autres caractères).

Si vous souhaitez minimiser l'ordre lexicographique du résultat, vous devez garder autant que possible les petits éléments devant. Si l'élément en haut de la pile stk est plus grand que l'élément actuellement traversé, selon les principes ci-dessus, cette situation doit être évitée si les conditions le permettent. Selon les exigences du sujet (déduplication), uniquement s'il y a un élément en haut de la pile ultérieurement Afin de retirer l'élément supérieur de la pile (réduire un ordre inverse). S'il n'y a pas un tel élément sur le dessus de la pile plus tard, il ne peut être conservé ici, même s'il est plus grand que son élément suivant.

class Solution {
    
    
public:
    string removeDuplicateLetters(string s) {
    
    
        string stk;
        size_t i = 0;
        for(size_t i = 0;i < s.size(); ++i)
        {
    
    
            if(stk.find(s[i]) != string::npos) continue;
            while(!stk.empty()&& stk.back() > s[i]&& 
                s.find(stk.back(), i) != string::npos)
                stk.pop_back();
            stk.push_back(s[i]);
        }
        return stk;
    }
};

Je suppose que tu aimes

Origine blog.csdn.net/u013354486/article/details/107955001
conseillé
Classement