文章:代码随想录
层序遍历:
思路:
BFS(Leecode有相关十道题都可以用层序遍历的思路,随想录可以看 已都做完)
通过队列来实现,对于每个节点依次在队列后面加入它的左节点和右子节点.那么怎么知道当前层有多少个节点呢?(需要pop多少次呢?)
那这个次数就由未开始for循环的队列的size来记录 因为for循环开始后,会加入节点的下一层的左右孩子,队列的size会不断改变,所以要先先记录队列的size来保证循环次数正确。 然后依次pop正确次数后,pop出来的就是当前层的节点.
public static List<List<Integer>> levelOrder(TreeNode root) {
Queue<TreeNode> level=new LinkedList<>();
List<List<Integer>> result=new ArrayList<>();
if(root==null){return result;}
level.offer(root);
while (!level.isEmpty()){
ArrayList<Integer> eachLevel = new ArrayList<>();
//因为for循环中level.size会改变,会加入下一层的节点.所以这里要先记录它的size。
//这时候它的size还是当前层的节点个数
int size=level.size();
for (int i = 0; i < size; i++) {
TreeNode top= level.poll();
eachLevel.add(top.val);
//加入下一层节点,空节点不入队列
if(top.left!=null){level.offer(top.left);}
if(top.right!=null){level.offer(top.right); }
}
result.add(eachLevel);
}
return result;
}
DFS:
思路:
--递归方式
是通过depth深度来标识是树的第几层,同时这也代表着结果集里的索引位置,比如第0层的元素要加入Lsit[0]位置的list中。
代码:
public List<List<Integer>> resList = new ArrayList<List<Integer>>();
public List<List<Integer>> levelOrderDFS(TreeNode root) {
checkFun01(root,0);
return resList;
}
public void checkFun01(TreeNode node, Integer deep) {
if (node == null) return;
//第一次遍历到这个深度时,需要给结果集先加入一个空的集合,不然后面会报空指针
if (resList.size() <= deep) {
//当层级增加时,list的Item也增加,利用list的索引值进行层级界定
List<Integer> item = new ArrayList<Integer>();
resList.add(item);
}
resList.get(deep ).add(node.val);
deep++;
checkFun01(node.left, deep);
checkFun01(node.right, deep);
}
翻转二叉树:
思路:
递归法(前后序遍历) 但是这种写法,中序不行,为什么呢?
中序是左中右,试想一下,我们先把左子树的所有孩子交换后,我们这时候把根节点的左右孩子交换再去遍历右子树, 那这时候根节点的右子树就变成了之前的左子树,那右子树的孩子就没交换还是处理的左子树,之前处理的左子树的孩子也会交换回来。
代码:
public TreeNode invertTreePre(TreeNode root) {
if (root==null){return root;}
TreeNode temp=root.left;
root.left=root.right;
root.right=temp;
invertTreePre(root.left);
invertTreePre(root.right);
return root;
}
public TreeNode invertTreePost(TreeNode root) {
if (root==null){return root;}
invertTreePost(root.left);
invertTreePost(root.right);
TreeNode temp=root.left;
root.left=root.right;
root.right=temp;
return root;
}
重温前一天的迭代方式来做前序遍历:
//非递归 栈 前序
public TreeNode invertTreeStPre(TreeNode root) {
// if(root==null){return root;}
Stack<TreeNode> record=new Stack<>();
//因为如果为null就push,下面的while会报空指针异常,或者前面直接判断为空return也可以.
if(root!=null){record.push(root);}
while (!record.empty()){
TreeNode node=record.pop();
if(node!=null){
if(node.right!=null){record.push(node.right);}
if(node.left!=null){record.push(node.left);}
record.push(node);
record.push(null);
}else {
TreeNode top= record.pop();
TreeNode temp=top.left;
top.left=top.right;
top.right=temp;
}
}
return root;
}
层序:
同时也可以用今天学的层序遍历来做:
//层序遍历方式
public TreeNode invertTreeLevelOrder(TreeNode root) {
if (root==null){return root;}
Queue<TreeNode> levelRecord=new LinkedList<>();
levelRecord.offer(root);
while (!levelRecord.isEmpty()){
int size= levelRecord.size();
for (int i = 0; i < size; i++) {
TreeNode top = levelRecord.poll();
TreeNode temp=top.left;
top.left=top.right;
top.right=temp;
if(top.left!=null){levelRecord.offer(top.left);}
if(top.right!=null){levelRecord.offer(top.right);}
}
}
return root;
}
对称二叉树:
思路:
这道题要对比每一层的外侧和内侧是否都相同。
递归法:
这道题只能用后序遍历,因为要对比完左右孩子才能返回中节点,如果先处理了中节点,那么就会缺少左孩子或者右孩子的信息,那么这时候返回中节点就没意义 //所以只能用后序遍历.
public boolean isSymmetric(TreeNode root) {
if (root == null) {
return true;
}
return compare(root.left, root.right);
}
private boolean compare(TreeNode left, TreeNode right) {
if (left != null && right == null) {
return false;
}
if (left == null && right != null) {
return false;
}
if (left == null && right == null) {
return true;
}
//null要在前面就判断不然会报空指针.
if (left.val != right.val) {
return false;
}
//比较外侧
boolean outside = compare(left.left, right.right);
//比较内侧
boolean inside = compare(left.right, right.left);
//这也是为什么只能用后序,试想把result这个中序放到左(outside)/右(inside)之前,结果都会变得无意义。
boolean result=outside && inside;
//两者都为true时才为true
return result;
}
非递归法,迭代:
--队列
思路:其实用层序遍历的思路转变一下,可以定义两个指针来改变压入队列的元素的顺序,然后两两抛出看看匹不匹配.
代码:
public boolean isSymmetricQueue(TreeNode root) {
if (root == null) {
return true;
}
Queue<TreeNode> levelRecord = new LinkedList<>();
levelRecord.offer(root.left);
levelRecord.offer(root.right);
while (!levelRecord.isEmpty()) {
//这里并不需要层序输出,或者对每一层的结果进行处理,只需要两两对比
// 所以不需要用for循环记录size,一直到队列内没有元素就可以
TreeNode leftNode = levelRecord.poll();
TreeNode rightNode = levelRecord.poll();
//判断条件
//如果都为空,则开始下一个循环,要遍历完全部元素判断才知道最终结果.
if (leftNode==null && rightNode==null) {
continue;
}
// if(leftNode!=null && rightNode==null){return false;}
// if(leftNode==null && rightNode!=null){return false;}
// if(leftNode.val!=rightNode.val){return false;}
//这里可以将上述三个条件合并,因为一开始已经判断了两者都为空的情况.
if(leftNode==null|| rightNode==null || leftNode.val!=rightNode.val){return false;}
//注意压入顺序
//外侧
levelRecord.offer(leftNode.left);
levelRecord.offer(rightNode.right);
//内测
levelRecord.offer(leftNode.right);
levelRecord.offer(rightNode.left);
}
return true;
}