JZ18 二叉树的镜像
(简单)
题目
描述
操作给定的二叉树,将其变换为源二叉树的镜像。
比如: 源二叉树
8
/ \
6 10
/ \ / \
5 7 9 11
镜像二叉树
8
/ \
10 6
/ \ / \
11 9 7 5
示例
输入:
{8,6,10,5,7,9,11}
返回值:
{8,10,6,11,9,7,5}
思路
方法一:
根据题目描述,将树转换为镜像二叉树的操作即将树结构的每一层的两个兄弟结点对换位置,(其实此题也没严谨地限定范围是完全二叉树,更没交代此类情况如何处理,因此,我们就按完全二叉树做就可以),因此操作是一层一层来进行的,因此,我们可以将每层的一对兄弟结点的(当然,最后也可能有一个结点没有兄弟结点,即对应另一结点为 null)操作放在循环中完成,因此,我们可以利用二叉树的广度优先遍历来完成,即借助一个队列,在循环的同时来实现对每层中结点的暂时存储,每次循环中出队列一个结点,操作其左右孩子结点进行对换,直至队列中不再有结点。
(补充:其实在树结构中,严格来说应该叫做层序遍历,类似的,广度优先遍历在图数据结构中经常使用,若您有需要,可参考之前文章:
Java实现【邻接矩阵、邻接表的创建、遍历(DFS,BFS)】+图解+完整代码
)
方法二:
此题也可用树的递归遍历(前、中、后序遍历)去实现,在遍历的同时进行镜像操作。
(补充:此部分的知识,如果您有需要,可参考之前文章:数据结构【完整代码】之(C语言实现【二叉树】创建、递归遍历(前序、中序、后序)、非递归先序遍历))
实现
class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
public class Solution {
//方法一
public TreeNode Mirror (TreeNode pRoot) {
if (pRoot == null) {
return null;
}
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.add(pRoot);
while (!queue.isEmpty()) {
TreeNode node = queue.poll();
if (node.left != null) {
queue.add(node.left);
}
if (node.right != null) {
queue.add(node.right);
}
TreeNode tempNode = node.left;
node.left = node.right;
node.right = tempNode;
}
return pRoot;
}
//方法二
public TreeNode Mirror_inOrder(TreeNode root) {
if (root == null)
return null;
Mirror_inOrder(root.left);
//子节点交换
TreeNode temp = root.left;
root.left = root.right;
root.right = temp;
//上面交换过了,这里root.right要变成root.left
Mirror_inOrder(root.left);
return root;
}
public TreeNode Mirror_postOrder(TreeNode root) {
if (root == null)
return null;
TreeNode left = Mirror_postOrder(root.left);
TreeNode right = Mirror_postOrder(root.right);
root.left = right;
root.right = left;
return root;
}
}
此处未自定义测试方法,直接用的此题平台上的测试机制。
JZ20 包含min函数的栈
(简单)
题目
描述
定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数,并且调用 min函数、push函数 及 pop函数 的时间复杂度都是 O(1)
push(value):将value压入栈中
pop():弹出栈顶元素
top():获取栈顶元素
min():获取栈中最小元素
示例:
输入: [“PSH-1”,“PSH2”,“MIN”,“TOP”,“POP”,“PSH1”,“TOP”,“MIN”]
输出: -1,2,1,-1
解析:
"PSH-1"表示将-1压入栈中,栈中元素为-1
"PSH2"表示将2压入栈中,栈中元素为2,-1
“MIN”表示获取此时栈中最小元素==>返回-1
"TOP"表示获取栈顶元素==>返回2
"POP"表示弹出栈顶元素,弹出2,栈中元素为-1
"PSH-1"表示将1压入栈中,栈中元素为1,-1
"TOP"表示获取栈顶元素==>返回1
“MIN”表示获取此时栈中最小元素==>返回-1
示例
输入:
[“PSH-1”,“PSH2”,“MIN”,“TOP”,“POP”,“PSH1”,“TOP”,“MIN”]
返回值:
-1,2,1,-1
思路
关于此题,我的第一思路是这样的,用一个栈来存数据,并做基本的入栈出栈操作,同时,另设两个存储当前最小值和最顶端值的变量,但当我写到红框区域的逻辑时,我突然意识到,若出栈的为最小值结点,那么之后的最小节点值如何处理,此处将会比较繁琐,并且还需再设新的数据结构进行存储,例如增设一个链表,每次进栈,用来存储当前最小的的结点值,每次出栈,若当前出栈结点为最小值结点,则同时删除链表中的最后结点,并将新修改的链表的最后一个结点赋值给当前最小值的变量。
但我总感觉这样麻烦了,而且似乎也不是这个题的出题目的——考察栈,因为我的思路已经又引入了链表这一数据结构(当然,用数组存也可以),并且还可能导致时间复杂度超出题目要求的情况,因此我十分不确定这个题目的解题思路是否和我想的一样,我便看了题解,果然,官方给出了一种十分巧妙的方法,将两个数组抽象成两个栈来解决问题——首先需要一个主栈normal,用于栈的正常操作,然后需要一个辅助栈minval,专门用于获取最小值,每当入栈一个新数据时,便将此数据入主栈,若此数据比辅助栈中的顶部数据值小,则将也将其入辅助栈,否则辅助栈将再次压入一遍其顶部栈的值,即当前栈中最小值,而对于出栈操作,则当主栈出栈一个数据时,辅助栈也应出栈一个数据,这就保证了两个栈的最小值的一致性,另外,还需考虑一些临界问题的判断和检验,具体在代码中添加逻辑即可,思路的图示操作如下。
实现
public class Solution {
int[] stack = new int[100];
int top = -1;
int[] stackMin = new int[100];
int topMin = -1;
public void push(int node) {
if (top > stack.length - 1) {
//栈满
throw new ArrayIndexOutOfBoundsException("栈满,不可再将新数据入栈");
}
stack[++top] = node;
if (topMin == -1) {
stackMin[++topMin] = node;
} else {
if (stackMin[topMin] < node) {
int temp = stackMin[topMin];
stackMin[++topMin] = temp;
} else {
stackMin[++topMin] = node;
}
}
}
public void pop() {
stack[top--] = 0;
stackMin[topMin--] = 0;
}
public int top() {
return stack[top];
}
public int min() {
return stackMin[topMin];
}
}