②子问题思路:
?代码如下:
//以子问题思路写
int size(BTNode root){
if(root==null){
return 0;
}
return size(root.left)+size(root.right)+1;
}
两种思考方式:
①遍历实现:
代码:
//以遍历的方式访问
int count1=0;
int getLeafNodeCount(BTNode root){
// int count1=0;
if(root==null){
return 0;
}else if(root.left==null && root.right==null){
count1++;
}
getLeafNodeCount(root.left);
getLeafNodeCount(root.right);
return count1;
}
②子问题思路:
代码如下:
int getLeafNodeCount(BTNode root){
if(root==null){
return 0;
}else if(root.left==null && root.right==null){
return 1;
}
return getLeafNodeCount(root.left)+getLeafNodeCount(root.right);
}
}
? ? ?该题在2中第二个思路中已经求得
?解题思路:
代码如下:
//求第K层结点的个数
public int getKLevelNodeCount(int k){
return getKLevelNodeCount(root, k);
}
// 获取第K层结点的个数
private int getKLevelNodeCount(BTNode root,int k){
if(root==null || k<=0){
return 0;
}
if(k==1){
return 1;
}
return getKLevelNodeCount(root.left, k-1)+getKLevelNodeCount(root.right, k-1);
}
思路分析:
代码如下:
// 获取二叉树的高度(时间复杂度为O(n))
int getHeight(BTNode root){
if(root==null){
return 0;
}
int leftHeight=getHeight(root.left);
int rightHeight=getHeight(root.right);
//此处用的是三目运算符求取两者中的较大值
return leftHeight>rightHeight?leftHeight+1:rightHeight+1;
}
解题思路:
代码如下 :
// 检测值为value的元素是否存在
boolean find(BTNode root, int val) {
if (root == null) {
return false;
} else if (root.val == val) {
return true;
}
if (find(root.left, val) || find(root.right, val)) {
return true;
}
return false;
}
解题思路:
代码如下:
boolean isCompleteTree(BTNode root){
if(root == null) return true;
Queue<BTNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
BTNode cur = queue.poll();
if(cur != null) {
queue.offer(cur.left);
queue.offer(cur.right);
}else {
break;
}
}
while (!queue.isEmpty()) {
BTNode top = queue.peek();
if(top != null) {
return false;
}
queue.poll();
}
return true;
}
100. 相同的树 - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/same-tree/
解题思路:
? ?要判断两棵树是否相同:?
? ?①数的结构相同
? ?②相应位置的结点对应的数值相同
代码如下:
public boolean isSameTree(TreeNode p, TreeNode q ){
if(p == null && q != null || p != null && q == null) {
return false;
}
if(p == null && q == null) {
return true;
}
if(p.val != q.val) {
return false;
}
//p != null && q!= null && p.val == q.val
return isSameTree(p.left,q.left) && isSameTree(p.right,q.right);
}
572. 另一棵树的子树 - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/subtree-of-another-tree/
代码如下:
public boolean isSubtree(TreeNode root, TreeNode subRoot) {
if(root == null || subRoot == null) {
return false;
}
//根节点和subroot是不是两颗相同的树
if(isSameTree(root,subRoot)) {
return true;
}
//subRoot是不是root的左子树
if(isSubtree(root.left,subRoot)) {
return true;
}
if(isSubtree(root.right,subRoot)) {
return true;
}
return false;
}
}
104. 二叉树的最大深度 - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/
?同二叉树基本操作的5题,请参考此篇博客上方
110. 平衡二叉树 - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/balanced-binary-tree/submissions/
解题思路:?
class Solution {
public int height (TreeNode root) {
if(root == null) {return 0;}
int leftHeight = height(root.left);
int rightHeight = height(root.right);
return (leftHeight > rightHeight) ?
(leftHeight+1) :(rightHeight+1);
}
/**
时间复杂度:O(N^2)
*/
public boolean isBalanced(TreeNode root) {
if(root == null) return true;
int left = height(root.left);
int right = height(root.right);
return Math.abs(left-right) <= 1 && isBalanced(root.left) && isBalanced(root.right);
}
}
5. 对称二叉树
101. 对称二叉树 - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/symmetric-tree/解题思路:
代码如下:
class Solution {
public boolean isSymmetric(TreeNode root) {
if(root == null) return true;
return isSymmetricChild(root.left,root.right);
}
public boolean isSymmetricChild(TreeNode leftTree,TreeNode rightTree) {
//第一种情况
if(leftTree == null && rightTree == null) return true;
//第二种情况
if((leftTree == null && rightTree != null)||(leftTree != null && rightTree == null)) return false;
//第三种情况
if(leftTree.val != rightTree.val) return false;
return isSymmetricChild(leftTree.left,rightTree.right) &&
isSymmetricChild(leftTree.right,rightTree.left);
}
102. 二叉树的层序遍历 - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/binary-tree-level-order-traversal/
解题思路:
借助一个队列和一个临时变量cur来打印分层遍历
①讨论根是否为空的情况
②当队列不为空时,出队列中的队尾元素到cur中,并通过cur.val进行打印
③循环讨论子左右子树的情况,所以要用while进行循环
两类代码:
①普通代码:
//打印层序遍历二叉树
public void levelOrder(TreeNode root) {
Queue<TreeNode> queue = new LinkedList<>();
//①判断树是否为空的情况
if(root == null) return;
queue.offer(root);
//②判断队列是否为空
while (!queue.isEmpty()) {
TreeNode cur = queue.poll();
System.out.print(cur.val+" ");
if(cur.left != null) {
queue.offer(cur.left);
}
if(cur.right != null) {
queue.offer(cur.right);
}
}
}
②OJ上解题的代码:
解题思路:?
代码如下:
//层序遍历访问打印元素
List<List<Integer>> ret = new ArrayList<>();
if(root == null) return ret;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
//当前的结点个数size
int size = queue.size();
List<Integer> list = new ArrayList<>();
while (size != 0) {
TreeNode cur = queue.poll();
//将同层结点放在一个list中
list.add(cur.val);
if(cur.left != null) {
queue.offer(cur.left);
}
if(cur.right != null) {
queue.offer(cur.right);
}
size--;//1 0
}
//将所有一层link的结点放在同一个list中
ret.add(list);
}
//最后返回整个所需的ret
return ret;
}
236. 二叉树的最近公共祖先 - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/
解题思路:
思路①:由二叉搜索树的思想来设计二叉树的方法
若是二叉搜索树
详细思路:
1.root==p || root==q(p,q为结点)
此时的最近公共祖先是root
2.可能均在根的左边或者右边
①p.val<root.val && q.val<root.val(p,q均在root的左子树中)
最近公共祖先在左子树中
②p.val>root.val && q.val>root.val(p,q均在root的右子树中)
最近公共祖先在右子树中
3.最近的公共祖先就是root
①p.val>root.val && q.val<root.val(p在左子树中,q在右子树中)
②p.val<root.val && q.val>root.val(p在右子树中,q在左子树中)
?代码如下:
//二叉树的最近公共祖先
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null){
return null;
}if(root==p||root==q){
return root;
}
TreeNode l=lowestCommonAncestor(root.left,p,q);
TreeNode r=lowestCommonAncestor(root.right,p,q);
if(l!=null && r!=null){
return root;
}else if(l!=null){
return l;
}else{
return r;
}
}
}
?思路②:
由孩子双亲表示法来求取?
代码如下:
class Solution {
//root:
public boolean getPath(TreeNode root,TreeNode node,Stack<TreeNode>stack){
if(root==null || node==null){
return false;
}stack.push(root);
if(root==node){
return true;
}
boolean flg=getPath(root.left,node,stack);
if(flg==true){
return true;
}
flg=getPath(root.right,node,stack);
if(flg==true){
return true;
}
stack.pop();
return false;
}
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null){
return null;
}
Stack<TreeNode> stack1=new Stack<>();
getPath(root,p,stack1);
Stack<TreeNode> stack2=new Stack<>();
getPath(root,q,stack2);
int size1=stack1.size();
int size2=stack2.size();
if(size1>size2){
int size=size1-size2;
while(size!=0){
stack1.pop();
size--;
}
while(!stack1.isEmpty() && !stack2.isEmpty()){
//用等号判断地址
if(stack1.peek()==stack2.peek()){
return stack1.pop();
}else{
stack1.pop();
stack2.pop();
}
}
}else{
int size=size2-size1;
while(size!=0){
stack2.pop();
size--;
}
while(!stack1.isEmpty() && !stack2.isEmpty()){
//用等号判断地址
if(stack1.peek()==stack2.peek()){
return stack1.pop();
}else{
stack1.pop();
stack2.pop();
}
}
}
return null;
}
}
牛客网链接https://www.nowcoder.com/practice/947f6eb80d944a84850b0538bf0ec3a5?tpId=13&&tqId=11179&rp=1&ru=/activity/oj&qru=/ta/coding-interviews/question-ranking解题思路:
前面已介绍过二叉搜索树的特点(因此已知当二叉搜索树中序遍历时是有序的)
①中序遍历这棵二叉树
②双向链表
?代码如下:
public class Solution {
//先写出一个中序遍历
TreeNode prev=null;
public void inOrder(TreeNode pCur){
if(pCur==null)return ;
inOrder(pCur.left);
pCur.left=prev;
if(prev!=null){
prev.right=pCur;
}
prev=pCur;
inOrder(pCur.right);
}
public TreeNode Convert(TreeNode pRootOfTree) {
if(pRootOfTree==null){
return null;
}
inOrder(pRootOfTree);
TreeNode head=pRootOfTree;
while(head.left!=null){
head=head.left;
}
return head;
}
}
105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/
解题思路:
①找到根结点
②通过中序遍历找到左右子树
③分别创建左右子树
代码如下:
class Solution {
//将preIndex设置为全局变量用来保证在递归的过程中当子树根结点返回到总根后的空指针异常
public int preIndex=0;
public TreeNode createTreeByPandI(int[]preorder,int[]inorder,int inbegin,int inend){
if(inbegin>inend){
//左树或者右树为空
return null;
}
TreeNode root=new TreeNode(preorder[preIndex]);
int rootIndex=findIndexOfI(inorder,inbegin,inend,preorder[preIndex]);
if(rootIndex==-1){
return null;
}
preIndex++;
root.left=createTreeByPandI(preorder,inorder,inbegin,rootIndex-1);
root.right=createTreeByPandI(preorder,inorder,rootIndex+1,inend);
return root;
}
private int findIndexOfI(int[]inorder,int inbegin,int inend,int key){
for(int i=inbegin;i<=inend;i++){
if(inorder[i]==key){
return i;
}
}
return -1;
}
public TreeNode buildTree(int[] preorder, int[] inorder) {
if(preorder==null||inorder==null){
return null;
}return createTreeByPandI(preorder,inorder,0,inorder.length-1);
}
}
106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/解题思路:
与上个题的不同点:
①postIndex是在最右边(即根结点由后序遍历的话,先后往前进行遍历)
②先访问右树后访问左树
代码如下:
class Solution {
public int postIndex=0;
public TreeNode createTreeByPandI(int[]inorder,int[]postorder,int inbegin,int inend){
if(inbegin>inend){
//左树或者右树为空
return null;
}
TreeNode root=new TreeNode(postorder[postIndex]);
int rootIndex=findIndexOfI(inorder,inbegin,inend,postorder[postIndex]);
if(rootIndex==-1){
return null;
}
postIndex--;
//分别创建右子树和左子树
root.right=createTreeByPandI(inorder,postorder,rootIndex+1,inend);
root.left=createTreeByPandI(inorder,postorder,inbegin,rootIndex-1);
return root;
}
private int findIndexOfI(int[]inorder,int inbegin,int inend,int key){
for(int i=inbegin;i<=inend;i++){
if(inorder[i]==key){
return i;
}
}
return -1;
}
public TreeNode buildTree(int[] inorder, int[] postorder) {
postIndex=postorder.length-1;
if(postorder==null||inorder==null){
return null;
}return createTreeByPandI(inorder,postorder,0,inorder.length-1);
}
}
606. 根据二叉树创建字符串 - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/construct-string-from-binary-tree/
解题思路:
?代码如下:
class Solution {
public void treeToString(TreeNode t,StringBuilder sb) {
if(t == null) return;
sb.append(t.val);
if(t.left != null) {
sb.append("(");
treeToString(t.left,sb);
sb.append(")");
}else {
//t.left == null
if(t.right == null) {
return;
}else{
sb.append("()");
}
}
if(t.right == null) {
return;
}else{
sb.append("(");
treeToString(t.right,sb);
sb.append(")");
}
}
public String tree2str(TreeNode root) {
if(root == null) return null;
StringBuilder sb = new StringBuilder();
treeToString(root,sb);
return sb.toString();
}
}
144. 二叉树的前序遍历 - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/binary-tree-preorder-traversal/submissions/
解题思路:
?
代码如下:
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer>ret=new ArrayList<>();
Stack<TreeNode>stack=new Stack<>();
TreeNode cur = root;
while (cur != null || !stack.isEmpty()) {
while (cur != null) {
stack.push(cur);
ret.add(cur.val);
cur = cur.left;
}
TreeNode top = stack.pop();
System.out.print(top.val+" ");
cur = top.right;
}
return ret;
}
94. 二叉树的中序遍历 - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/binary-tree-inorder-traversal/
解题思路:同13的前序非递归的遍历实现
代码如下:
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> ret= new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
while (cur != null || !stack.isEmpty()) {
if (cur != null) {
stack.push(cur);
cur = cur.left;
} else {
cur = stack.pop();
ret.add(cur.val);
cur = cur.right;
}
}
return ret;
}
}
?