Análisis de ideas de resolución de problemas de Leetcode (33) 235-241

  1. El ancestro común más cercano
    de un árbol de búsqueda binario Dado un árbol de búsqueda binario, encuentre el ancestro común más cercano de dos nodos especificados en el árbol.

Un problema muy simple, solución recursiva: para un árbol de búsqueda binario, subárbol izquierdo <raíz <subárbol derecho, se puede juzgar si dos nodos están ubicados en dos lados o en el mismo lado. Si está en ambos lados, la raíz es el antepasado común más cercano; de lo contrario, continúe buscando

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */

class Solution {
    
    
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
    
    
        if (root->val == p->val || root->val == q->val)
        {
    
    
            return root;
        }
        if ((root->val > p->val && root->val < q->val)
        || (root->val < p->val && root->val > q->val))
        {
    
    
            return root;
        }

        if (root->val > p->val && root->val > q->val)
        {
    
    
            return lowestCommonAncestor(root->left, p, q);
        }
        else
        {
    
    
            return lowestCommonAncestor(root->right, p, q);
        }
    }
};
  1. El ancestro común más cercano
    de un árbol binario Dado un árbol binario, encuentre el ancestro común más cercano de dos nodos especificados en el árbol.

Esta pregunta es un poco más problemática en comparación con la pregunta anterior, porque no hay ninguna característica de un árbol de búsqueda binaria. Por lo tanto, cuando se pasa a la recursividad, debe comenzar desde abajo. Si está satisfecho de que hay un nodo en el subárbol izquierdo y el subárbol derecho de una raíz determinada, se devuelve el nodo raíz. De lo contrario, uno de los dos nodos debe ser un ancestro común.

class Solution {
    
    
public:
    TreeNode* ans;
    bool dfs(TreeNode* root, TreeNode* p, TreeNode* q) {
    
    
        if (root == nullptr) return false;
        bool lson = dfs(root->left, p, q);
        bool rson = dfs(root->right, p, q);
        if ((lson && rson) || ((root->val == p->val || root->val == q->val) && (lson || rson))) {
    
    
            ans = root;
        } 
        return lson || rson || (root->val == p->val || root->val == q->val);
    }
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
    
    
        dfs(root, p, q);
        return ans;
    }
};

Otro enfoque es registrar el nodo principal de cada nodo y luego encontrar el nodo raíz común para los dos nodos.

class Solution {
    
    
public:
    unordered_map<int, TreeNode*> fa;
    unordered_map<int, bool> vis;
    void dfs(TreeNode* root){
    
    
        if (root->left != nullptr) {
    
    
            fa[root->left->val] = root;
            dfs(root->left);
        }
        if (root->right != nullptr) {
    
    
            fa[root->right->val] = root;
            dfs(root->right);
        }
    }
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
    
    
        fa[root->val] = nullptr;
        dfs(root);
        while (p != nullptr) {
    
    
            vis[p->val] = true;
            p = fa[p->val];
        }
        while (q != nullptr) {
    
    
            if (vis[q->val]) return q;
            q = fa[q->val];
        }
        return nullptr;
    }
};

  1. Eliminación de un nodo en una lista vinculada
    Escriba una función para eliminar un nodo dado (no final) en una lista vinculada, y solo se le dará el nodo solicitado para ser eliminado.

La parte interesante de esta pregunta es que la lista enlazada individualmente no sabe cómo el nodo anterior borra el nodo, el método es asignar el nodo actual al siguiente y borrar el siguiente.

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
    
    
public:
    void deleteNode(ListNode* node) {
    
    

        if (node == NULL)
            return;

        if (node->next == NULL)
        {
    
    
            node = NULL;
            return;
        }

        ListNode *tmp = node->next;
        node->val = node->next->val;
        node->next = node->next->next;
        delete tmp;
        return;
    }
};
  1. El producto de matrices distintas a sí misma
    le da una matriz entera nums de longitud n, donde n> 1, devuelve la salida de matriz de salida, donde la salida [i] es igual al producto de los elementos restantes en nums excepto nums [i].

La solución a este problema restringe la incapacidad de usar la división, por lo que puede cambiar de opinión: use dos matrices para almacenar el producto del elemento izquierdo y el producto del elemento derecho en la posición actual, y luego multiplique los dos. Se puede simplificar aún más: use la matriz de salida para almacenar el elemento izquierdo primero, y luego obtenga dinámicamente el elemento derecho y multiplique directamente la asignación.

class Solution {
    
    
public:
    vector<int> productExceptSelf(vector<int>& nums) {
    
    
        int length = nums.size();
        vector<int> answer(length);

        // answer[i] 表示索引 i 左侧所有元素的乘积
        // 因为索引为 '0' 的元素左侧没有元素, 所以 answer[0] = 1
        answer[0] = 1;
        for (int i = 1; i < length; i++) {
    
    
            answer[i] = nums[i - 1] * answer[i - 1];
        }

        // R 为右侧所有元素的乘积
        // 刚开始右边没有元素,所以 R = 1
        int R = 1;
        for (int i = length - 1; i >= 0; i--) {
    
    
            // 对于索引 i,左边的乘积为 answer[i],右边的乘积为 R
            answer[i] = answer[i] * R;
            // R 需要包含右边所有的乘积,所以计算下一个结果时需要将当前值乘到 R 上
            R *= nums[i];
        }
        return answer;
    }
};


  1. Valor máximo de la ventana deslizante
    Dados los números de una matriz, una ventana deslizante de tamaño k se mueve desde el lado más a la izquierda de la matriz hasta el lado más a la derecha de la matriz. Solo puede ver los k números en la ventana deslizante. La ventana deslizante solo se mueve una posición hacia la derecha a la vez.
    Devuelve el valor máximo en la ventana deslizante.

Use la cola para guardar la ventana. El extremo frontal de la variable (es decir, window.front ()) es el subíndice del valor máximo de este recorrido. Cuando encontremos un nuevo número, agregaremos el nuevo número al final de la cola de elementos dobles (también Es la comparación window.back ()). Si el final es más pequeño que el nuevo número, el final se desecha hasta que el final de la cola sea más grande que el nuevo número o la cola esté vacía. El enfoque es un poco como usar la pila para emparejar corchetes.

class Solution {
    
    
public:
	vector<int> maxSlidingWindow(vector<int>& nums, int k) {
    
    
        if (k == 0) return {
    
    };
		vector<int> res;
		deque<size_t> window;
		/*Init K integers in the list*/
		for (size_t i = 0; i < k; i++) {
    
    
			while (!window.empty()  && nums[i] > nums[window.back()]) {
    
    
				window.pop_back();
			}
			window.push_back(i);
		}
		res.push_back(nums[window.front()]);
		/*End of initialization*/
		for (size_t i = k; i < nums.size(); i++) {
    
    
			if (!window.empty() && window.front() <= i - k) {
    
    
				window.pop_front();
			}
			while (!window.empty() && nums[i] > nums[window.back()]) {
    
    
				window.pop_back();
			}
			window.push_back(i);
			res.push_back(nums[window.front()]);
		}
		return res;
	}
};


  1. Buscar matriz bidimensional 2
    Escriba un algoritmo eficiente para buscar un objetivo de valor objetivo en la matriz de matriz mxn. La matriz tiene las siguientes características:
    los elementos de cada fila están dispuestos en orden ascendente de izquierda a derecha.
    Los elementos de cada columna están dispuestos en orden ascendente de arriba a abajo.

Esta pregunta es una búsqueda binaria típica, pero debido a que ha sido ordenada, además de la búsqueda binaria, también se puede completar con el principio de las líneas diagonales: comenzando desde la esquina superior derecha o la esquina inferior izquierda, mueva las filas y columnas de acuerdo con las reglas de tamaño hasta encontrar o fuera de los límites

class Solution {
    
    
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
    
    
        if(matrix.size() == 0||matrix[0].size() == 0)
        {
    
    
            return  false;
        }
        int  curx = matrix.size()-1,cury = 0;
        while(curx >= 0 &&cury < matrix[0].size())
        {
    
    
            if(target > matrix[curx][cury])
            {
    
    
                cury++;
            }
            else  if(target < matrix[curx][cury])
            {
    
    
                curx--;
            }
            else
            {
    
    
                return  true;
            }
        }
        return  false;
    }
};


  1. Diseño de precedencia para expresiones de operación
    Dada una cadena que contiene números y operadores, agregue paréntesis a la expresión y cambie la precedencia de operación para encontrar resultados diferentes. Necesitas dar el resultado de todas las combinaciones posibles. Los operadores válidos incluyen +, - y *.

Esta pregunta puede usar el algoritmo de dividir y conquistar para desarmar la expresión en partes separadas por coincidencia y luego encontrar diferentes soluciones en orden. Otro enfoque es tratarlo como una solución de programación dinámica: use dos listas, una para todos los números y otra para todos los operadores. dp [i] [j] representa todas las soluciones de la expresión en el rango del i-ésimo al j-ésimo número (contando desde 0).

class Solution {
    
    
public:
    vector<int> diffWaysToCompute(string input) {
    
    
        int index = 0;
        int num = 0;
        while(index < input.size() && isdigit(input[index]))
            num = num * 10 + input[index++] - '0';
        if(index == input.size()){
    
    
            hash[input] = {
    
    num};
            return {
    
    num};
        }
        vector<int> ans;
        for(int i = 0; i < input.size(); i++){
    
    
            if(isOp(input[i])){
    
    
                string s1 = input.substr(0,i);
                string s2 = input.substr(i);
                vector<int> result1, result2;
                if(!hash.count(s1))
                    result1 = diffWaysToCompute(input.substr(0,i));
                else
                    result1 = hash[s1];
                if(!hash.count(s2))
                    result2 = diffWaysToCompute(input.substr(i+1));
                else
                    result2 = hash[s2];
                for(int r1 : result1){
    
    
                    for(int r2 : result2){
    
    
                        ans.push_back(calculate(r1,input[i],r2));
                    }
                }
            }
        }
        hash[input] = ans;
        return ans;
    }

    bool isOp(const char& c){
    
    
        return c == '+' || c == '-' || c == '*';
    }

    int calculate(const int& num1, const char& op, const int& num2){
    
    
        if(op == '+')
            return num1 + num2;
        else if(op == '-')
            return num1 - num2;
        else
            return num1 * num2;
    }
private:
    unordered_map<string,vector<int>> hash;
};


Supongo que te gusta

Origin blog.csdn.net/u013354486/article/details/107226044
Recomendado
Clasificación