题目19:请完成一个函数,输入一个二叉树,该函数输出它的镜像。二叉树结点定义如下。
public class TreeNode{
public int value;
public TreeNode leftNode;
public TreeNode rightNode;
public TreeNode() {}
public TreeNode(int value) {
this.value = value;
}
}
分析:
为了能够形成直观的印象,可以自己画一颗二叉树,然后根据照镜子的经验画出它的镜像。如下图所示。
可以看出,这两棵树根结点相同,但左右两个子结点交换了位置,因此不妨直接交换根结点的两个子节结点。如下图a所示。之后发现10和6结点的子结点保持不变,继续交换这两个结点的子结点,如下图b和c所示。此变换之后的树就是原树的镜像。
可得出求一棵树的镜像的过程:先遍历这棵树的每个结点,如果遍历到的结点有子结点,就交换它的两个子节点,当交换完所有非叶子结点的左右结点之后,就得到了树的镜像。
代码如下所示:
public static void mirrorRecursively(TreeNode pNode){
if (pNode == null ) return;
if (pNode.leftNode == null && pNode.rightNode == null )return;
TreeNode temp = pNode.leftNode;
pNode.leftNode = pNode.rightNode;
pNode.rightNode = temp;
if(pNode.leftNode != null) mirrorRecursively(pNode.leftNode);
if(pNode.rightNode != null )mirrorRecursively(pNode.rightNode);
}
为了测试,使用下面这个辅助函数:
public static ArrayList<Integer> printFromTopToBottom(TreeNode pTreeRoot) {
ArrayList<Integer> list = new ArrayList<Integer>();
if (pTreeRoot == null) {
return null;
}
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(pTreeRoot);
while (!queue.isEmpty()) {
TreeNode treeNode = queue.poll();
if (treeNode.leftNode != null) {
queue.offer(treeNode.leftNode);
}
if (treeNode.rightNode != null) {
queue.offer(treeNode.rightNode);
}
list.add(treeNode.value);
}
return list;
}
测试:
public static void main(String[] args) {
TreeNode pNode1 = new TreeNode(8);
TreeNode pNode2 = new TreeNode(6);
TreeNode pNode3 = new TreeNode(10);
TreeNode pNode4 = new TreeNode(5);
TreeNode pNode5 = new TreeNode(7);
TreeNode pNode6 = new TreeNode(9);
TreeNode pNode7 = new TreeNode(11);
pNode1.leftNode = pNode2;
// pNode1.rightNode = pNode3;
pNode2.leftNode = pNode4;
pNode2.rightNode = pNode5;
// pNode3.leftNode = pNode6;
// pNode3.rightNode = pNode7;
mirrorRecursively(pNode1);
System.out.println(printFromTopToBottom(pNode1));
// 只有一个结点
TreeNode node = new TreeNode(8);
mirrorRecursively(node);
System.out.println(printFromTopToBottom(node));
// 空结点
mirrorRecursively(null);
}
题目21:定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的min函数,在该栈中,调用min、push及pop的时间复杂度都是O(1)。
分析:
可能会想到在栈里添加一个成员变量存放最小值的元素,每次压入一个新元素的时候,如果该元素比当前最小的元素还要小,则更新最小元素。但是当最小元素被弹出栈时,如何找到下一个最小元素呢?
是不是可以把每次的最小元素(之前的最小元素和压入栈的新元素两者的较小值)都保存到另外一个辅助栈里呢?分析过程如下表所示。首先往空的栈里压入元素3,显然现在最小值是3,把最小值压入辅助栈;接着往数据栈里压入4,最小值仍为3,所以依然往辅助栈压入3;继续往数据栈里压入2,此时最小元素时2,因此往辅助栈里压入2…当把最小元素从数据栈弹出时,同时弹出辅助栈的栈顶元素,此时辅助栈的栈顶元素就是下一个最小值。
步骤 | 操作 | 数据栈 | 辅助栈 | 最小值 |
---|---|---|---|---|
1 | 压入3 | 3 | 3 | 3 |
2 | 压入4 | 3,4 | 3,3 | 3 |
3 | 压入2 | 3,4,2 | 3 ,3,2 | 2 |
4 | 压入1 | 3,4,2,1 | 3 ,3,2,1 | 1 |
5 | 弹出 | 3,4,2 | 3 ,3,2 | 2 |
6 | 弹出 | 3,4 | 3,3 | 3 |
7 | 压入0 | 3,4,0 | 3,3,0 | 0 |
代码如下所示:
private static Stack<Integer> stack = new Stack();
private static Stack<Integer> minSatck = new Stack();
public static void push(int value) {
stack.push(value);
if (minSatck.size() == 0 || value < minSatck.peek())
minSatck.push(value);
else
minSatck.push(minSatck.peek());
}
public static void pop() {
if (stack.size() == 0 && minSatck.size() == 0) throw new RuntimeException("栈是空的");
stack.pop();
minSatck.pop();
}
public static Integer min() {
if (stack.size() == 0 && minSatck.size() == 0) throw new RuntimeException("栈是空的");
return minSatck.peek();
}
public static void main(String[] args) {
push(5);
push(6);
System.out.println(min());
push(4);
push(1);
System.out.println(min());
}