剑指 Offer 27. 二叉树的镜像
当遍历到root的左右结点时,交换左右结点,就是镜像操作了,所以最经典的还是递归操作了。
本题和226. 翻转二叉树为一种题型,方法相同。
class Solution {
public TreeNode mirrorTree(TreeNode root) {
//递归
if(root == null){return null;}
TreeNode left = mirrorTree(root.left);
TreeNode right = mirrorTree(root.right);
root.left = right;
root.right = left;
return root;
}
}
第二种就是用栈,队列都可以,和递归一样,就是遍历所有结点,交换左右结点。
class Solution {
public TreeNode mirrorTree(TreeNode root) {
if(root == null){return null;}
Deque<TreeNode> stack = new LinkedList<TreeNode>();
stack.push(root);
while(!stack.isEmpty()){
TreeNode node = stack.pop();
if(node.left!=null){stack.push(node.left);}
if(node.right!=null){stack.push(node.right);}
TreeNode cur = node.left;
node.left = node.right;
node.right=cur;
}
return root;
}
}
剑指 Offer 28. 对称的二叉树
递归,check函数,判断子树的左结点等于右节点,右节点等于左节点,即对称
class Solution {
public boolean isSymmetric(TreeNode root) {
return check(root, root);
}
public boolean check(TreeNode p, TreeNode q) {
if (p == null && q == null) {
return true;
}
if (p == null || q == null) {
return false;
}
return p.val == q.val && check(p.left, q.right) && check(p.right, q.left);
}
}
迭代,对root的两个子树,进行对称比较。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isSymmetric(TreeNode root) {
if(root == null){
return true;
}
Deque<TreeNode> deque = new LinkedList<TreeNode>();
deque.add(root.left);
deque.add(root.right);
while(!deque.isEmpty()){
TreeNode left = deque.remove();
TreeNode right = deque.remove();
if(left==null&&right==null){
continue;
}
if(left==null||right==null){
return false;
}
if(left.val!=right.val){
return false;
}
deque.add(left.left); //核心:左子树的左节点和右子树的右节点
deque.add(right.right); //左子树的右节点和右子树的左节点进行比较
deque.add(left.right);
deque.add(right.left);
}
return true;
}
}
104. 二叉树的最大深度
最大深度其实就和层序遍历一样,从根节点依次往下遍历,每一层全部遍历,找到下一层的所有结点,根据结点的多少,来删除当前层并添加下一层。
class Solution {
public int maxDepth(TreeNode root) {
if(root == null){
return 0;
}
int max = 0;
Deque<TreeNode> deque= new LinkedList<>();
deque.add(root);
while(!deque.isEmpty()){
max++;
int size = deque.size();
for(int i =0;i<size;i++){
TreeNode node = deque.remove();
if(node.right!=null){deque.add(node.right);}
if(node.left!=null){deque.add(node.left);}
}
}
return max;
}
}
看了看递归,唉,为什么就学不会递归呢。(好简单)
class Solution {
public int maxDepth(TreeNode root) {
return root == null?0:Math.max(maxDepth(root.left),maxDepth(root.right))+1;
}
}
112. 路径总和
这个题感觉就像是求两数之和一样,只不过不是数组了,变成了栈或队列。首先,先用栈搞了一遍,确实用时和内存都不是太好。
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
if(root == null){
return false;
}
Stack<TreeNode> stack1 = new Stack<TreeNode>();
Stack<Integer> stack2 = new Stack<Integer>();
//用两个栈一个存结点一个存数值
stack1.push(root);
stack2.push(root.val);
while(!stack1.isEmpty()){
TreeNode node = stack1.pop();
int sum = stack2.pop();
if(node.left==null&&node.right==null&&sum==targetSum){
return true;
}//结点往下遍历,sum累加。
if(node.right!=null){
stack1.push(node.right);
stack2.push(sum+node.right.val);
}
if(node.left!=null){
stack1.push(node.left);
stack2.push(sum+node.left.val);
}
}
return false;
}
}
队列与上面栈同理.
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
if(root == null){
return false;
}
Deque<TreeNode> queue1 = new LinkedList<TreeNode>();
Deque<Integer> queue2 = new LinkedList<Integer>();
queue1.add(root);
queue2.add(root.val);
while(!queue1.isEmpty()){
TreeNode node = queue1.remove();
int sum = queue2.remove();
if(node.left==null&&node.right==null&&sum==targetSum){
return true;
}
if(node.left!=null){
queue1.add(node.left);
queue2.add(sum+node.left.val);
}if(node.right!=null){
queue1.add(node.right);
queue2.add(sum+node.right.val);
}
}
return false;
}
}
递归
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
if(root == null){
return false;
}
if(root.left == null && root.right == null){
return targetSum == root.val;
}
return hasPathSum(root.left, targetSum - root.val) || hasPathSum(root.right, targetSum - root.val);
}//让tar每向下遍历一次,tar减去当前root.val,直到相等为true。
}
二叉树有很多分类,二叉搜索树便是其中一种,二叉搜索树有一个最关键的定义就是:根节点/父节点的左子树上的节点都比根节点/父节点小,而右子树上的节点都比根节点/父节点要大。所以根据这个做题就可以变得简单一些。
700. 二叉搜索树中的搜索
因为左子树小于根节点,右子树大于根节点,所以根据这些来判断当前结点和val的值,找到后直接输出root,即是余下的子树。(核心就是val大于根节点,往右走,val小于根节点,往左走)。
class Solution {
public TreeNode searchBST(TreeNode root, int val) {
while(root!=null&&root.val!=val){
if(root.val>val){
root = root.left;
}
else if(root.val<val){
root = root.right;
}
}
return root;
}
}
当然,也可以递归判断。
class Solution {
public TreeNode searchBST(TreeNode root, int val) {
if (root == null) {
return null;
}
if (val == root.val) {
return root;
}
return searchBST(val < root.val ? root.left : root.right, val);
}
}
01. 二叉搜索树中的插入操作
本题也是如此,先判断根节点和value的大小,然后依次往下继续搜索,如果当前结点大于value,往左,否则往右,直到下一节点为空,然后插入新节点并且值为value。
class Solution {
public TreeNode insertIntoBST(TreeNode root, int val) {
if(root == null){
return new TreeNode(val);
}
TreeNode cur = root;
while(cur!=null){
if(cur.val>val){
if(cur.left==null){
cur.left = new TreeNode(val);
break;
}else{
cur=cur.left;
}
}
else{
if(cur.right == null){
cur.right = new TreeNode(val);
break;
}else{
cur=cur.right;
}
}
}
return root;
}
}
递归
class Solution {
public TreeNode insertIntoBST(TreeNode root, int val) {
if(root == null){
return new TreeNode(val);
}
TreeNode node = root;
if(node.val>val){
node.left = insertIntoBST(node.left,val);
}
else{
node.right = insertIntoBST(node.right,val);
}
return root;
}
}
653. 两数之和 IV - 输入二叉搜索树
和数组的两数之和也类似,
创建一个哈希表和一个队列,将根节点加入队列中,然后执行以下步骤:
从队列中取出队头,假设其值为 x;检查哈希表中是否存在 k−x,如果存在,返回 True;否则,将该节点的左右的非空子节点加入队尾;重复以上步骤,直到队列为空;如果队列为空,说明树上不存在两个和为 k 的节点,返回 False。
class Solution {
public boolean findTarget(TreeNode root, int k) {
if(root == null){
return false;
}
Set<Integer> set = new HashSet<>();
Deque<TreeNode> deque = new LinkedList<>();
deque.offer(root);
while(!deque.isEmpty()){
TreeNode node = deque.poll();
if(set.contains(k-node.val)){
return true;
}
set.add(node.val);
if(node.left!=null){
deque.offer(node.left);
}
if(node.right!=null){
deque.offer(node.right);
}
}
return false;
}
}
递归
class Solution {
Set<Integer> set = new HashSet<Integer>();
public boolean findTarget(TreeNode root, int k) {
if (root == null) {
return false;
}
if (set.contains(k - root.val)) {
return true;
}
set.add(root.val);
return findTarget(root.left, k) || findTarget(root.right, k);
}
}
因为二叉搜索树是左<中<右的,而中序遍历是左中右的,所以二叉搜索树中序遍历之后的结果,就是一个升序数组,而升序数组就是前面的两数之和的计算了。
class Solution {
List<Integer> list = new ArrayList<Integer>();
public boolean findTarget(TreeNode root, int k) {
inorderTraversal(root);
int left = 0, right = list.size() - 1;
while (left < right) {
if (list.get(left) + list.get(right) == k) {
return true;
}
if (list.get(left) + list.get(right) < k) {
left++;
} else {
right--;
}
}
return false;
}
public void inorderTraversal(TreeNode node) {
if (node == null) {
return;
}
inorderTraversal(node.left);
list.add(node.val);
inorderTraversal(node.right);
}
}