LeetCode刷题之旅(中等 -4):100. 相同的树

2019年9月15日

继续弥补《数据结构与算法》的不足,今天抽中了“树”。决定先把基础题做一遍,打好基础。

目录

题目:

解决方法1:

解决思路:

性能结果:

解决方法2:

思路:深度优先遍历

解决方法3:

迭代

复杂度分析

递归

复杂度分析


题目:

LeetCode刷题之旅(中等 -4):100. 相同的树_第1张图片

 

二叉树基础概念:

树是一种抽象数据类型(ADT)或是实现这种抽象数据类型的数据结构,用来模拟具有树状结构性质的数据集合。它是由 n(n>0)n(n>0) 个有限节点组成一个具有层次关系的集合。

把它叫做「树」是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。

它具有以下的特点:

  • 每个节点都只有有限个子节点或无子节点;
  • 没有父节点的节点称为根节点;
  • 每一个非根节点有且只有一个父节点;
  • 除了根节点外,每个子节点可以分为多个不相交的子树;
  • 树里面没有环路。

LeetCode刷题之旅(中等 -4):100. 相同的树_第2张图片

解决方法1:

package leetCode.tree;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * REMARK 相同的树
 *
 * @author: mmb
 * @date: 19-9-15
 */
public class TwoSameTreeSolution {

    public static void main(String[] args){
		TreeNode p = getATree();
//		TreeNode q = getATree();
		TreeNode q = getATreeV2();
		System.out.println("result = " + isSameTree(p, q));

	}

	/**
	 * 比较两棵树是否相同
	 */
    public static boolean isSameTree(TreeNode p, TreeNode q){
		List tree1AllNodes = getAllNodes(p);
		List tree2AllNodes = getAllNodes(q);
		System.out.println("tree1AllNodes = " + tree1AllNodes);
		System.out.println("tree2AllNodes = " + tree2AllNodes);
		return compareTwoTree(tree1AllNodes, tree2AllNodes);
    }

    /**
	 * 比较两棵树的结点列表
	 */
	private static boolean compareTwoTree(List tree1AllNodes, List tree2AllNodes) {
		// 两棵树的节点要一样
		if (tree1AllNodes.size() == tree2AllNodes.size()){
			int countTime = 0;
			int tree1NotNullCount = 0;
			int tree2NotNullCount = 0;
			Iterator iterator1 = tree1AllNodes.iterator();
			Iterator iterator2 = tree2AllNodes.iterator();
			// 逐个遍历两棵树的节点
			while (iterator1.hasNext()){
				Integer tree1Node = iterator1.next();
				Integer tree2Node = iterator2.next();

				// 两棵树的节点都不为空
				if (tree1Node != null && tree2Node != null){
					if (tree1Node.equals(tree2Node)){
						countTime++;
						continue;
					} else {
						break;
					}
				}
				// 两棵树的节点都为空
				else if (tree1Node == null && tree2Node == null) {
					continue;
				}
				// 其中一棵树节点为空
				else {
					break;
				}
			}

			// tree1的非空节点
			for (Integer node : tree1AllNodes){
				if (node != null){
					tree1NotNullCount++;
				}
			}
			// tree2的非空节点
			for (Integer node : tree2AllNodes){
				if (node != null){
					tree2NotNullCount++;
				}
			}

			// tree1和tree2和节点比较相同次数一样
			if (tree1NotNullCount == countTime && tree2NotNullCount == countTime){
				return true;
			}
		}
		return false;
	}

	/**
	 * 获取所有节点数据
	 */
	private static List getAllNodes(TreeNode node){
		// 前序遍历,递归获取所有节点信息
		ArrayList treeNodes = new ArrayList<>();
		if(node != null){
			treeNodes.add(node.val);
			if (node.left != null){
				List allLeftNodes = getAllNodes(node.left);
				treeNodes.addAll(allLeftNodes);
			} else if (node.right != null){
				treeNodes.add(null);
			}

			if (node.right != null){
				List allRightNodes = getAllNodes(node.right);
				treeNodes.addAll(allRightNodes);
			}

		}
		return treeNodes;
	}

	/**
	 * 创建一棵树
	 */
    public static TreeNode getATree(){
		TreeNode headNode = new TreeNode(1);
		TreeNode leftNode = new TreeNode(2);
		TreeNode rightNode = new TreeNode(3);
		headNode.setLeft(leftNode);
		headNode.setRight(rightNode);
		return headNode;
	}
    public static TreeNode getATreeV2(){
		TreeNode headNode = new TreeNode(1);
		TreeNode leftNode = new TreeNode(2);
		TreeNode rightNode = new TreeNode(3);
		headNode.setLeft(leftNode);
		headNode.setRight(rightNode);
		return headNode;
	}

}

解决思路:

  • 对于给定的两棵树,我是首先想到的是递归遍历(这里使用前序遍历:根节点-左子树-右子树),也就是说将树的所有节点全部拿出到list里面;第二步,就是逐个对比list的节点是否相同;
  • 这种方法比较笨,我这种初学者往往会往死胡同里面走;这时候算法体现出优越性了。。。

性能结果:

LeetCode刷题之旅(中等 -4):100. 相同的树_第3张图片

解决方法2:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isSameTree(TreeNode p, TreeNode q) {
        if(p == null && q == null) 
            return true;
        if(p == null || q == null) 
            return false;
        if(p.val != q.val) 
            return false;
        return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
    }
}

作者:guanpengchn
链接:https://leetcode-cn.com/problems/same-tree/solution/hua-jie-suan-fa-100-xiang-tong-de-shu-by-guanpengc/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

思路:深度优先遍历

终止条件与返回值:

  • 当两棵树的当前节点都为 null 时返回 true
  • 当其中一个为 null 另一个不为 null 时返回 false
  • 当两个都不为空但是值不相等时,返回 false

执行过程:当满足终止条件时进行返回,不满足时分别判断左子树和右子树是否相同,其中要注意代码中的短路效应

时间复杂度:O(n),n 为树的节点个数

 

解决方法3:

迭代

  • 最简单的策略是使用递归。检查p和q节点是否不是空,它们的值是否相等。如果所有检查都正常,则递归地为子节点执行相同操作。
class Solution {
  public boolean isSameTree(TreeNode p, TreeNode q) {
    // p 和 q 均为 null时
    if (p == null && q == null) return true;
    // p 或 q 有一个为null时
    if (q == null || p == null) return false;
    if (p.val != q.val) return false;
    return isSameTree(p.right, q.right) &&
            isSameTree(p.left, q.left);
  }
}

作者:gaohanghang
链接:https://leetcode-cn.com/problems/same-tree/solution/xiang-tong-de-shu-by-gaohanghang/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

复杂度分析

时间复杂度:O(N),其中N是树中的节点数,因为每个节点只访问一次。

空间复杂度:O(log(N)):

在最佳情况下即completely balanced tree空间复杂度是O(log(N)),

在最坏情况下 completely unbalanced tree空间复杂度是O(N),和递归次数保持一致。

 

递归

  • 思路:从根开始,在每次迭代时将当前节点弹出deque。

  • 然后执行与方法1中相同的检查:p 和 q 不为空,p.val 和 q.val 相等,如果检查正常,则push子节点。

class Solution {
  public boolean check(TreeNode p, TreeNode q) {
    // p and q are null
    if (p == null && q == null) return true;
    // one of p and q is null
    if (q == null || p == null) return false;
    if (p.val != q.val) return false;
    return true;
  }

  public boolean isSameTree(TreeNode p, TreeNode q) {
    if (p == null && q == null) return true;
    if (!check(p, q)) return false;

    // init deques
    ArrayDeque deqP = new ArrayDeque();
    ArrayDeque deqQ = new ArrayDeque();
    deqP.addLast(p);
    deqQ.addLast(q);

    while (!deqP.isEmpty()) {
      p = deqP.removeFirst();
      q = deqQ.removeFirst();

      if (!check(p, q)) return false;
      if (p != null) {
        // in Java nulls are not allowed in Deque
        if (!check(p.left, q.left)) return false;
        if (p.left != null) {
          deqP.addLast(p.left);
          deqQ.addLast(q.left);
        }
        if (!check(p.right, q.right)) return false;
        if (p.right != null) {
          deqP.addLast(p.right);
          deqQ.addLast(q.right);
        }
      }
    }
    return true;
  }
}

作者:gaohanghang
链接:https://leetcode-cn.com/problems/same-tree/solution/xiang-tong-de-shu-by-gaohanghang/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

复杂度分析

时间复杂度 :O(N) 因为每个节点只访问一次
空间复杂度:O(log(N)), 在最佳情况下即completely balanced tree空间复杂度是O(log(N)),在最坏情况下 completely unbalanced tree空间复杂度是O(N)

 

你可能感兴趣的:(LeetCode题库)