leetcode算法练习——102 层序遍历 226.翻转二叉树 101.对称二叉树

leetcode

102 层序遍历(图论里广度优先搜索)

题目链接
二叉树本身结构是无法做到层序遍历的 因为又要保存元素的孩子元素 又要保存该元素所在层次——故利用队列来保存我们遍历过的元素
层序遍历

  1. 根结点6加入到队列中 队列中为6 size记录队列大小为1(也代表本层有几个元素)
  2. 6弹出队列 6的左右孩子入队列 队列为4 7 size=2
  3. 弹出两个元素 因为size为2 先弹出4 为6 4 size变为1 而后将4的左右孩子入队列 队列中7 1 3
  4. 弹出7 为6 4 7 size为0 而后将7的左右孩子入队列 队列中1 3 5 8 size为4
  5. 弹出1 3 5 8 因为已经是最后一层了
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    // 二维数组
    public List<List<Integer>> resList = new ArrayList<List<Integer>>();

    public List<List<Integer>> levelOrder(TreeNode root) {
        checkFun02(root);
        return resList;
    }

    //BFS--迭代方式--借助队列
    public void checkFun02(TreeNode node) {
        // 判断有无根结点
        if (node == null) return;
        // 创建队列
        Queue<TreeNode> que = new LinkedList<TreeNode>();
        // 将根结点存入队列中
        que.offer(node);
        // 队列为空 那就意味着没有元素添加进来了 层序遍历就结束了
        while (!que.isEmpty()) {
            // 用一个一维数组来存放每一层的元素 一层一个数组 最后返回的结果应该是个二维数组
            List<Integer> itemList = new ArrayList<Integer>();
            // 记录当前层结点的个数 用来控制队列里弹出结点的个数
            int len = que.size();
            // 遍历每一层的元素 那么size大小应该>0
            while (len > 0) {
                // 获取队列的第一个元素
                TreeNode tmpNode = que.poll();
                // 把元素存入数组中
                itemList.add(tmpNode.val);
                // 将结点的左右孩子加入队列中
                if (tmpNode.left != null) que.offer(tmpNode.left);
                if (tmpNode.right != null) que.offer(tmpNode.right);
                len--;
            }
            // 存入二维数组中
            resList.add(itemList);
        }

    }
}

226.翻转二叉树

题目链接
应该用递归还是用层序?递归的话用前中后哪一种——用前序或者后序是最方便的

  1. 确实递归函数的返回值和参数:返回值是结点定义 参数就是传入的根结点
  2. 确定终止条件:碰到空结点的时候
  3. 处理逻辑:

前序:根左右——要处理的是交换root的左右孩子 swap(root.left,root.right) (root指的是遍历的每一个结点 不一定是树的根结点) 而后向左 向右遍历invertTree(root.left); invertTree(root.right);

后序:和前序逻辑类似 只是最后invertTree顺序不一致

但是中序——如果将swap放在invertTree左右之中 因为先左孩子交换孩子 再根交换孩子(做完后,右孩子已经变成了原来的左孩子) 再右孩子交换孩子(此时其实是对原来的左孩子做交换)若要用中序可以写成处理两次invertTree左边

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    // 后序
    public TreeNode invertTree(TreeNode root) {
        if (root == null) {
            return null;
        }
        invertTree(root.left);
        invertTree(root.right);
        swapChildren(root);
        return root;
    }

    private void swapChildren(TreeNode root) {
        TreeNode tmp = root.left;
        root.left = root.right;
        root.right = tmp;
    }
}

101.对称二叉树

题目链接
思路:

  • 本质上是判断二叉树根结点的左右子树是否可以相互翻转
  • 如何判断左右子树能否翻转呢——比较的是外侧的结点是否相等 + 内侧的结点是否相等
    对称二叉树

应该用递归还是用层序?递归的话用前中后哪一种

  • 只能使用后序:后序是根左右 因为要不断收集左右孩子的信息返回给上一个结点 这样才能知道是否可以互相翻转
  • 假设如果使用中序:左根右 那么左子树处理完了 返回给中结点了 右子树还不知道具体如何了
  • 假设如果使用前序:根左右 那么一上来就处理左右字数了 不知道到底能不能翻转
    要收集孩子信息 并向上一层返回 必须要用后序遍历
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public boolean isSymmetric(TreeNode root) {
        // 判断根结点的左右子树是否可以翻转 作为参数传入
        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;
        }
        // 左右值不相等
        if (left.val != right.val) {
            return false;
        }
        // 左右结点都不为空 且值相等 那就要继续遍历下去
        // 是从最下面开始比较的
        // 比较外侧 左结点的左孩子vs右结点的右孩子
        boolean compareOutside = compare(left.left, right.right);
        // 比较内侧 
        boolean compareInside = compare(left.right, right.left);
        // 告诉父结点 是否对称
        return compareOutside && compareInside;
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值