1. Descripción del tema
Enlace del problema: leetcode.cn/problems/zh…
Dificultad: Moderada
Ingrese los resultados del recorrido en orden previo y el recorrido en orden de un árbol binario, construya el árbol binario y devuelva su nodo raíz.
Suponga que ni el recorrido en orden previo de entrada ni los resultados del recorrido en orden contienen números duplicados.
2. Ideas para resolver problemas
divide y conquistaras
Preordenar propiedades transversales: los nodos se [ 根节点 | 左子树 | 右子树 ]
ordenan por .
Propiedades transversales en orden: los nodos se [ 左子树 | 根节点 | 右子树 ]
ordenan por .
Con base en las propiedades anteriores, se pueden extraer las siguientes inferencias:
El primer valor del recorrido en orden previo es el valor del nodo raíz. Use este valor para dividir el resultado del recorrido en orden en dos partes. La parte izquierda es el resultado del recorrido en orden del subárbol izquierdo del árbol, y la parte derecha es el resultado de recorrido en orden del subárbol derecho del árbol. Luego resuelva recursivamente los subárboles izquierdo y derecho respectivamente.
Para resolver este tipo de problemas, es adecuado utilizar la idea de divide y vencerás.El código de divide y vencerás se puede resumir en la siguiente estructura:
def divide_conquer(problem, param1, param2, ...):
# 1.终止条件
if problem is None:
print_result
return
# 2.准备数据
data = prepare_data(problem)
subproblems = split_problem(problem, data)
# 3.处理子问题
subresult1 = self.divide_conquer(subproblems[0], p1, ...)
subresult2 = self.divide_conquer(subproblems[1], p1, ...)
subresult3 = self.divide_conquer(subproblems[1], p1, ...)
# ...
result = process_result(subresult1, subresult2, subresult3, ...)
Análisis del algoritmo divide y vencerás:
-
Condiciones de terminación: el índice del nodo raíz en el recorrido en orden previo
root
, el límite izquierdo del subárbol en el recorrido en ordenpreL
y el límite derecho del subárbol en el recorrido en ordenpreR
; cuandopreL > preR
significa que el nodo hoja se ha cruzado, se devuelve nulo en este momento; -
Preparar datos:
- Cree un nodo raíz
node
: el valor del nodo espreorder[root]
; - Divida los subárboles izquierdo y derecho: encuentre
inorder
el índice del nodo raíz en el recorrido en ordeni
;
- Cree un nodo raíz
-
Manejar subproblemas: habilitar la recursividad del subárbol izquierdo y derecho;
índice de nodo raíz Límite izquierdo de recorrido en orden Límites rectos transversales en orden subárbol izquierdo raíz + 1 izquierda yo - 1 subárbol derecho i - izquierda + raíz + 1 yo + 1 bien
Análisis de Complejidad
Complejidad temporal: O(N), donde N es el número de nodos del árbol. La inicialización de HashMap debe atravesar en orden, lo que toma O (N). Se establecen recursivamente un total de N nodos, y las operaciones de establecimiento y búsqueda de nodos en cada capa de recursividad toman O(1), por lo que se utiliza el tiempo O(N).
Complejidad del espacio: O(N), HashMap usa O(N) espacio adicional; en el peor de los casos (cuando el árbol binario de entrada es una lista enlazada), la profundidad de recurrencia alcanza N, ocupando el espacio del marco de pila O(N); por lo que un total de O(N) se usa N) espacio.
3. Implementación del código
// 缓存中序遍历数组每个值对应的索引
private Map<Integer, Integer> indexForInOrders = new HashMap<>();
public TreeNode reConstructBinaryTree(int[] pre, int[] in) {
for (int i = 0; i < in.length; i++)
indexForInOrders.put(in[i], i);
return reConstructBinaryTree(pre, 0, pre.length - 1, 0);
}
private TreeNode reConstructBinaryTree(int[] pre, int preL, int preR, int inL) {
if (preL > preR)
return null;
TreeNode root = new TreeNode(pre[preL]);
int inIndex = indexForInOrders.get(root.val);
int leftTreeSize = inIndex - inL;
root.left = reConstructBinaryTree(pre, preL + 1, preL + leftTreeSize, inL);
root.right = reConstructBinaryTree(pre, preL + leftTreeSize + 1, preR, inL + leftTreeSize + 1);
return root;
}
Lectura recomendada
la cubierta
Serie de algoritmos de hoy, dirección de actualización de la solución: studeyang.tech/2023/0718.h...