剑指Offer+第18题+树的子结构+java

题目描述

  输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)。

解题思路:

  首先看牛客网给出的测试用例:

  

   一般对于树的操作不像链表一样,操作更复杂,如果使用循环遍历的话,对于非完全二叉树规律难寻,一般通用的方法就是使用递归求解,本题也不例外,同样使用递归求解,求解的大体思路是首先判断B的根节点和A的根节点是否相同(这里的相同是指节点的值相同并且左右子节点相同),如果相同比较他们的左右子节点,这一步骤是相同的,可以用递归完成,直到B遍历到每个尾节点,如果这一过程比较的所有节点是相同的,则证明B是A的子结构。如果B的根节点和A的根节点不同,则A向他的左右子节点滑动,然后继续跟B的子节点比较,步骤同上。

  递归的使用可以用我总结的三步来完成。求解过程如下:

  1. 递归截止条件。

  递归的截止条件是为了递归能够避免无限循环下去,首先来分析什么情况下递归截止返回遍历结果,(1)根据题目要求,如果B数是个空树,递归截止。(2)如果被遍历的树A是空树,自然而然递归截止。(3)如果比较的是B的尾节点,无法进行下去,递归也会截止。(4)如果A树从头遍历到尾始终没有和B的节点相同的节点,递归截止。

  2. 递归的前后衔接。

  如果A的根节点值以及左右子节点情况和B的根节点完全相同,那么A和B都继续滑动到他们的左右子节点进行比较;如果A的根节点值和B的根节点值是相同的,但是左右子节点的情况是不相同的,那么只滑动A到他的左右子节点再与B比较。如果A的根节点的值和B的根节点的值不相同,那么A直接滑动到他的左右自己点再和B的根节点比较,直到遍历完成。

  3. 递归节点数据的处理。

  根据题目,本题目中用到的递归并没有数据处理,只是比较判断两个树节点是否相同。对于其他递归,可以具体情况具体对待。

代码:


public class Offer18 {
	
	public static class BinaryTreeNode{
		int value;
		BinaryTreeNode left;
		BinaryTreeNode right;
		
		BinaryTreeNode(){}
		
		BinaryTreeNode(int value){
			this.value = value;
		}
		
		BinaryTreeNode(int val, BinaryTreeNode left, BinaryTreeNode right){
			this.value = val;
			this.left = left;
			this.right = right;
		}
	}

	public boolean hasSubTree(BinaryTreeNode root1, BinaryTreeNode root2){
		if(root1 == null || root2 == null)
			return false;
		
		boolean result = false;
		
		if(root1 != null && root2 != null){
			if(root1.value == root2.value)
				result = doesTree1HaveTree2(root1, root2);
			if(!result)
				result = hasSubTree(root1.left,root2);
			if(!result)
				result = hasSubTree(root1.right, root2);
		}
		return result;
	}
	
	public boolean doesTree1HaveTree2(BinaryTreeNode root1, BinaryTreeNode root2) {
		if(root2 == null)//如果root2都检查完了,都匹配,则返回true
			return true;
		if(root1 == null) //如果root1都检查完了,不匹配,则返回false
			return false;
		if(root1.value != root2.value)
			return false;
		
		return doesTree1HaveTree2(root1.left, root2.left)&&doesTree1HaveTree2(root1.right, root2.right);
	}
	
	//为了使方便测试,这里封装了一个设置指定根节点的左孩子和右孩子节点的方法:
	public static void setSubTreeNode(BinaryTreeNode root, BinaryTreeNode left, BinaryTreeNode right){
		if(root == null)
			return;
		root.left = left;
		root.right = right;
	}

	public static void main(String[] args) {
		Offer18 of18 = new Offer18();
		//功能测试
		 // 01.树中结点含有分叉,树B是树A的子结构
	    //                  8                8
	    //              /       \           / \
	    //             8         7         9   2
	    //           /   \
	    //          9     2
	    //               / \
	    //              4   7
		BinaryTreeNode nodeA11 = new BinaryTreeNode(8);
		BinaryTreeNode nodeA12 = new BinaryTreeNode(8);
		BinaryTreeNode nodeA13 = new BinaryTreeNode(7);
		BinaryTreeNode nodeA14 = new BinaryTreeNode(9);
		BinaryTreeNode nodeA15 = new BinaryTreeNode(2);
		BinaryTreeNode nodeA16 = new BinaryTreeNode(4);
		BinaryTreeNode nodeA17 = new BinaryTreeNode(7);
		
		setSubTreeNode(nodeA11, nodeA12, nodeA13);
		setSubTreeNode(nodeA12, nodeA14, nodeA15);
		setSubTreeNode(nodeA15, nodeA16, nodeA17);
		
		BinaryTreeNode nodeB11 = new BinaryTreeNode(8);
		BinaryTreeNode nodeB12 = new BinaryTreeNode(9);
		BinaryTreeNode nodeB13 = new BinaryTreeNode(2);
		
		setSubTreeNode(nodeB11, nodeB12, nodeB13);
		
		System.out.println("情况1: "+of18.hasSubTree(nodeA11, nodeB11));
		
		// 02.树中结点含有分叉,树B不是树A的子结构
	    //                  8                8
	    //              /       \           / \
	    //             8         7         9   2
	    //           /   \
	    //          9     3
	    //               / \
	    //              4   7
		//注意如果创建使用函数二叉树,则必须逆序建立,先建立子节点,再逆序往上建立,因为非叶子结点会使用到下面的节点,
		//而初始化是按顺序初始化的,不逆序建立会报错;如果不适用函数创建二叉树,像下面这样做,不必用逆序建立
		BinaryTreeNode nodeA27 = new BinaryTreeNode(7,null,null);
		BinaryTreeNode nodeA26 = new BinaryTreeNode(4,null, null);
		BinaryTreeNode nodeA25 = new BinaryTreeNode(3, nodeA26, nodeA27);
		BinaryTreeNode nodeA24 = new BinaryTreeNode(9, null, null);
		BinaryTreeNode nodeA23 = new BinaryTreeNode(7, null, null);
		BinaryTreeNode nodeA22 = new BinaryTreeNode(8, nodeA24, nodeA25);
		BinaryTreeNode nodeA21 = new BinaryTreeNode(8, nodeA22, nodeA23);
		
		BinaryTreeNode nodeB23 = new BinaryTreeNode(2, null, null);
		BinaryTreeNode nodeB22 = new BinaryTreeNode(9, null, null);
		BinaryTreeNode nodeB21 = new BinaryTreeNode(8, nodeB22, nodeB23);
		
		System.out.println("情况2: "+of18.hasSubTree(nodeA21, nodeB21));
		
		//特殊输入测试
		 // 03.树中结点只有左子结点,树B是树A的子结构
	    //                8                  8
	    //              /                   / 
	    //             8                   9   
	    //           /                    /
	    //          9                    2
	    //         /      
	    //        2        
	    //       /
	    //      5
		BinaryTreeNode nodeA31 = new BinaryTreeNode(8);
		BinaryTreeNode nodeA32 = new BinaryTreeNode(8);
		BinaryTreeNode nodeA33 = new BinaryTreeNode(9);
		BinaryTreeNode nodeA34 = new BinaryTreeNode(2);
		BinaryTreeNode nodeA35 = new BinaryTreeNode(5);
		
		nodeA31.left = nodeA32;
		nodeA32.left = nodeA33;
		nodeA33.left = nodeA34;
		nodeA34.left = nodeA35;
		
		BinaryTreeNode nodeB31 = new BinaryTreeNode(8);
		BinaryTreeNode nodeB32 = new BinaryTreeNode(9);
		BinaryTreeNode nodeB33 = new BinaryTreeNode(2);
		
		nodeB31.left = nodeB32;
		nodeB32.left = nodeB33;
		
		System.out.println("情况3: "+of18.hasSubTree(nodeA31, nodeB31));
		
		 // 04.树中结点只有左子结点,树B不是树A的子结构
	    //                8                  8
	    //              /                   / 
	    //             8                   9   
	    //           /                    /
	    //          9                    3
	    //         /      
	    //        2        
	    //       /
	    //      5
		BinaryTreeNode nodeA41 = new BinaryTreeNode(8);
		BinaryTreeNode nodeA42 = new BinaryTreeNode(8);
		BinaryTreeNode nodeA43 = new BinaryTreeNode(9);
		BinaryTreeNode nodeA44 = new BinaryTreeNode(2);
		BinaryTreeNode nodeA45 = new BinaryTreeNode(5);
		
		nodeA41.left = nodeA42;
		nodeA42.left = nodeA43;
		nodeA43.left = nodeA44;
		nodeA44.left = nodeA45;
		
		BinaryTreeNode nodeB41 = new BinaryTreeNode(8);
		BinaryTreeNode nodeB42 = new BinaryTreeNode(9);
		BinaryTreeNode nodeB43 = new BinaryTreeNode(3);
		
		nodeB41.left = nodeB42;
		nodeB42.left = nodeB43;
		
		System.out.println("情况4: "+of18.hasSubTree(nodeA41, nodeB41));
		
		// 05.树中结点只有右子结点,树B是树A的子结构
	    //       8                   8
	    //        \                   \ 
	    //         8                   9   
	    //          \                   \
	    //           9                   2
	    //            \      
	    //             2        
	    //              \
	    //               5
		BinaryTreeNode nodeA51 = new BinaryTreeNode(8);
		BinaryTreeNode nodeA52 = new BinaryTreeNode(8);
		BinaryTreeNode nodeA53 = new BinaryTreeNode(9);
		BinaryTreeNode nodeA54 = new BinaryTreeNode(2);
		BinaryTreeNode nodeA55 = new BinaryTreeNode(5);
		
		nodeA51.right = nodeA52;
		nodeA52.right = nodeA53;
		nodeA53.right = nodeA54;
		nodeA54.right = nodeA55;
		
		BinaryTreeNode nodeB51 = new BinaryTreeNode(8);
		BinaryTreeNode nodeB52 = new BinaryTreeNode(9);
		BinaryTreeNode nodeB53 = new BinaryTreeNode(2);
		
		nodeB51.right = nodeB52;
		nodeB52.right = nodeB53;
		
		System.out.println("情况5: "+of18.hasSubTree(nodeA51, nodeB51));
		
		// 06.树中结点只有右子结点,树B不是树A的子结构
	    //       8                   8
	    //        \                   \ 
	    //         8                   9   
	    //          \                 / \
	    //           9               3   2
	    //            \      
	    //             2        
	    //              \
	    //               5
		BinaryTreeNode nodeA61 = new BinaryTreeNode(8);
		BinaryTreeNode nodeA62 = new BinaryTreeNode(8);
		BinaryTreeNode nodeA63 = new BinaryTreeNode(9);
		BinaryTreeNode nodeA64 = new BinaryTreeNode(2);
		BinaryTreeNode nodeA65 = new BinaryTreeNode(5);
		
		nodeA61.right = nodeA62;
		nodeA62.right = nodeA63;
		nodeA63.right = nodeA64;
		nodeA64.right = nodeA65;
		
		BinaryTreeNode nodeB61 = new BinaryTreeNode(8);
		BinaryTreeNode nodeB62 = new BinaryTreeNode(9);
		BinaryTreeNode nodeB63 = new BinaryTreeNode(3);
		BinaryTreeNode nodeB64 = new BinaryTreeNode(2);
		
		nodeB61.right = nodeB62;
		setSubTreeNode(nodeB62, nodeB63, nodeB64);
		
		System.out.println("情况6: "+of18.hasSubTree(nodeA61, nodeB61));
		
		// 07.树A为空树
		BinaryTreeNode nodeB71 = new BinaryTreeNode(8);
		BinaryTreeNode nodeB72 = new BinaryTreeNode(9);
		BinaryTreeNode nodeB73 = new BinaryTreeNode(3);
		BinaryTreeNode nodeB74 = new BinaryTreeNode(2);
		
		nodeB71.right = nodeB72;
		setSubTreeNode(nodeB72, nodeB73, nodeB74);
		
		System.out.println("情况7: "+of18.hasSubTree(null, nodeB71));
		
		 // 08.树B为空树
		BinaryTreeNode nodeA81 = new BinaryTreeNode(8);
		BinaryTreeNode nodeA82 = new BinaryTreeNode(8);
		BinaryTreeNode nodeA83 = new BinaryTreeNode(9);
		BinaryTreeNode nodeA84 = new BinaryTreeNode(2);
		BinaryTreeNode nodeA85 = new BinaryTreeNode(5);
		
		nodeA81.right = nodeA82;
		nodeA82.right = nodeA83;
		nodeA83.right = nodeA84;
		nodeA84.right = nodeA85;
		
		System.out.println("情况8: "+of18.hasSubTree(nodeA81, null));
		
		// 09.树A和树B都为空树
		System.out.println("情况9: "+of18.hasSubTree(null, null));
		
		
	}
}

运行结果:

情况1: true
情况2: false
情况3: true
情况4: false
情况5: true
情况6: false
情况7: false
情况8: false
情况9: false

我的代码托管到github上:https://github.com/HuangNobody/JianZhi_Offer

猜你喜欢

转载自blog.csdn.net/Quantum_Dog/article/details/87945102