剑指 Offer 07. 重建二叉树
题目
输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。
假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
示例 1:
Input: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
Output: [3,9,20,null,null,15,7]
示例 2:
Input: preorder = [-1], inorder = [-1]
Output: [-1]
限制:
0 <= 节点个数 <= 5000
方法一
递归:根据先序遍历和中序遍历的对应关系:首先创建一个哈希表,用来记录先序遍历中的每一个元素在中序遍历中的下标;接着根据先序遍历中的第一个元素找到其在中序遍历中的位置,中序遍历的第一个元素到该位置的前一个元素即为左子树,该位置的后一个元素到中序遍历的最后一个元素即为右子树。同理,根据中序遍历中的左右子树连续的元素个数,可以推断出先序遍历中哪些元素属于左子树的先序遍历,和中序遍历;然后递归创建即可。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
int[] preorder;
HashMap<Integer, Integer> hash = new HashMap<Integer,Integer>();
public TreeNode buildTree(int[] _preorder, int[] inorder) {
preorder = _preorder;
int n = inorder.length;
for (int i = 0; i < n; i ++ ) {
hash.put(inorder[i], i);
}
return dfs(0, n - 1, 0, n - 1);
}
public TreeNode dfs(int pl, int pr, int il, int ir) {
if (pl > pr) return null;
int index = hash.get(preorder[pl]);
TreeNode left = dfs(pl + 1, pl + index - il, il, index - 1);
TreeNode right = dfs(pl + index - il + 1, pr, index + 1, ir);
TreeNode root = new TreeNode(preorder[pl]);
root.left = left;
root.right = right;
return root;
}
}
时间复杂度: O(n)
空间复杂度: O(n)
剑指 Offer 09. 用两个栈实现队列
题目
用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail
和 deleteHead
,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead
操作返回 -1 )
示例 1:
输入:
["CQueue","appendTail","deleteHead","deleteHead"]
[[],[3],[],[]]
输出:[null,null,3,-1]
示例 2:
输入:
["CQueue","deleteHead","appendTail","appendTail","deleteHead","deleteHead"]
[[],[],[5],[2],[],[]]
输出:[null,-1,null,null,5,2]
提示:
1 <= values <= 10000
最多会对 appendTail、deleteHead 进行 10000 次调用
方法一
模拟:一个栈用来入队,另一个栈用来辅助出队。入队时往stk1
添加,出队时,判断stk2
中是否有元素,有则直接将栈顶元素弹出。没有则将stk1
中的元素全部弹到stk2
中之后,stk2
再弹出栈顶元素。若stk1
中也没有,则说明队列为空,返回-1。
class CQueue {
LinkedList<Integer> stk1;
LinkedList<Integer> stk2;
public CQueue() {
stk1 = new LinkedList<>();
stk2 = new LinkedList<>();
}
public void appendTail(int value) {
stk1.addLast(value);
}
public int deleteHead() {
if (stk2.isEmpty()) {
if (stk1.isEmpty()) return -1;
else {
while (!stk1.isEmpty()) {
stk2.addLast(stk1.removeLast());
}
}
}
return stk2.removeLast();
}
}
/**
* Your CQueue object will be instantiated and called as such:
* CQueue obj = new CQueue();
* obj.appendTail(value);
* int param_2 = obj.deleteHead();
*/
时间复杂度: O(1)
空间复杂度: O(n)
注意: 使用Stack的方式来做这道题,会造成速度较慢; 原因的话是Stack继承了Vector接口,而Vector底层是一个Object数组,那么就要考虑空间扩容和移位的问题了。 可以使用LinkedList来做Stack的容器,因为LinkedList实现了Deque接口,所以Stack能做的事LinkedList都能做,其本身结构是个双向链表,扩容消耗少。