基础算法之二叉树问题

基础算法之二叉树问题

这里是基础算法系列的第三部分



前言

本文章最主要介绍链表的各个问题。


二叉树相关问题

前序,中序,后续遍历

前序

递归
public static void preOrderRecur(Node node){
        if (node == null){
            return;
        }
        System.out.print(node.value + "  ");
        preOrderRecur(node.left);
        preOrderRecur(node.right);
    }

中前后

无递归
public static void preOrderUnRecur(Node head) {
		System.out.print("pre-order: ");
		if (head != null) {
			Stack<Node> stack = new Stack<Node>();
			stack.add(head);
			while (!stack.isEmpty()) {
				head = stack.pop();
				System.out.print(head.value + " ");
				if (head.right != null) {
					stack.push(head.right);
				}
				if (head.left != null) {
					stack.push(head.left);
				}
			}
		}
		System.out.println();
	}

注意:这里是先判断右后判断左。

中序

递归
public static void inOrderRecur(Node head) {
		if (head == null) {
			return;
		}
		inOrderRecur(head.left);
		System.out.print(head.value + " ");
		inOrderRecur(head.right);
	}

前中后

无递归
public static void inOrderUnRecur(Node head) {
		System.out.print("in-order: ");
		if (head != null) {
			Stack<Node> stack = new Stack<Node>();
			while (!stack.isEmpty() || head != null) {
				if (head != null) {
					stack.push(head);
					head = head.left;
				} else {
					head = stack.pop();
					System.out.print(head.value + " ");
					head = head.right;
				}
			}
		}
		System.out.println();
	}

注意:中序,没有右边的概念
在这里插入图片描述

后序

递归
public static void posOrderRecur(Node head) {
		if (head == null) {
			return;
		}
		posOrderRecur(head.left);
		posOrderRecur(head.right);
		System.out.print(head.value + " ");
	}

前后中

无递归
public static void posOrderUnRecur1(Node head) {
		System.out.print("pos-order: ");
		if (head != null) {
			Stack<Node> s1 = new Stack<Node>();
			Stack<Node> s2 = new Stack<Node>();
			s1.push(head);
			while (!s1.isEmpty()) {
				head = s1.pop();
				s2.push(head);
				if (head.left != null) {
					s1.push(head.left);
				}
				if (head.right != null) {
					s1.push(head.right);
				}
			}
			while (!s2.isEmpty()) {
				System.out.print(s2.pop().value + " ");
			}
		}
		System.out.println();
	}

注意:可以用两个栈,由中右左---->左右中
在这里插入图片描述

求一棵二叉树的宽度

通过:宽度优先遍历

public static int getMaxWidth(Node head) {
		if (head == null) {
			return 0;
		}
		int maxWidth = 0;
		int curWidth = 0;
		int curLevel = 0;
		HashMap<Node, Integer> levelMap = new HashMap<>();
		levelMap.put(head, 1);
		LinkedList<Node> queue = new LinkedList<>();
		queue.add(head);
		Node node = null;
		Node left = null;
		Node right = null;
		while (!queue.isEmpty()) {
			node = queue.poll();
			left = node.left;
			right = node.right;
			if (left != null) {
				levelMap.put(left, levelMap.get(node) + 1);
				queue.add(left);
			}
			if (right != null) {
				levelMap.put(right, levelMap.get(node) + 1);
				queue.add(right);
			}
			//初始化当前层数
			if (levelMap.get(node) > curLevel) {
				curWidth = 0;
				curLevel = levelMap.get(node);
			} else {
				curWidth++;
			}
			maxWidth = Math.max(maxWidth, curWidth);
		}
		return maxWidth;
	}

如何判断一颗二叉树是否是搜索二叉树?

思路:搜索二叉树的特点,在中序遍历下,严格遵守从大到小的顺序。

public static boolean isBST(Node head) {
		if (head == null) {
			return true;
		}
		LinkedList<Node> inOrderList = new LinkedList<>();
		//中序遍历
		process(head, inOrderList);
		int pre = Integer.MIN_VALUE;
		for (Node cur : inOrderList) {
			if (pre >= cur.value) {
				return false;
			}
			pre = cur.value;
		}
		return true;
	}

	public static void process(Node node, LinkedList<Node> inOrderList) {
		if (node == null) {
			return;
		}
		process(node.left, inOrderList);
		inOrderList.add(node);
		process(node.right, inOrderList);
	}

如何判断是否为完全二叉树

思路:通过层序遍历,然后判断是否出现下面两种情况:
①在出现叶节点情况下,还出现子节点为空
②在左节点为空,右结点不为空,
这些为非完全二叉树情况。

public static boolean isCBT(Node head) {
		if (head == null) {
			return true;
		}
		LinkedList<Node> queue = new LinkedList<>();
		boolean leaf = false;
		Node l = null;
		Node r = null;
		queue.add(head);
		while (!queue.isEmpty()) {
			head = queue.poll();
			l = head.left;
			r = head.right;
			//第一种情况:出现叶子结点,并且还出现了子节点不为空
			//第二种情况:在一个结点上,存在左结点为空,有节点不为空。这些都为不完全二叉树
			if ((leaf && (l != null || r != null)) || (l == null && r != null)) {
				return false;
			}
			if (l != null) {
				queue.add(l);
			}
			if (r != null) {
				queue.add(r);
			} else {
				leaf = true;
			}
		}
		return true;
	}

二叉树题目套路

如何判断是否为平衡二叉树?(二叉树题目套路)

通过递归方式:
①先设定一个终止条件
②对各个分支进行处理
③通过,各个分支返回上来的信息对本层信息进行处理
④返回本层的处理信息。

public static boolean isBalanced(Node head) {
		return process(head).isBalanced;
	}

	public static int levelBalanced(Node head) {
		return process(head).height;
	}

	public static class ReturnType {
		public boolean isBalanced;
		public int height;

		public ReturnType(boolean isB, int hei) {
			isBalanced = isB;
			height = hei;
		}
	}

	public static ReturnType process(Node x) {
		if (x == null) {
			return new ReturnType(true, 0);
		}
		ReturnType leftData = process(x.left);
		ReturnType rightData = process(x.right);
		int height = Math.max(leftData.height, rightData.height);
		boolean isBalanced = leftData.isBalanced && rightData.isBalanced
				&& Math.abs(leftData.height - rightData.height) < 2;
		return new ReturnType(isBalanced, height);
	}

找最小公共祖先结点?(二叉树题目套路)

public static Node lowestAncestor(Node head, Node o1, Node o2) {
		//选择终结条件时,就只考虑只有这一个结点。
		//
		if (head == null || head == o1 || head == o2) {
			return head;
		}
		Node left = lowestAncestor(head.left, o1, o2);
		Node right = lowestAncestor(head.right, o1, o2);
		//第一种情况两棵树都有返回值,这表明两个结点分散在自己的左右树上。
		if (left != null && right != null) {
			return head;
		}
		//若只有一个结点不为Null,则就返回那个,若都为null,则返回null
		return left != null ? left : right;
	}

在二叉树中找到一个节点的后继节点

全新的Node: 该结构比普通二叉树节点结构多了一个指向父节点的parent指针.
问题:只给一个在二叉树中的某个节点node,请实现返回node的后继节点的函数.
后继结点:在二叉树的中序遍历的序列中, node的下一个节点叫作node的后继节点。

解决思路:后继结点分为两种情况:①此结点有右分支,那么其后继节点在右数的最左结点。② 若此结点没有右分支,那么其后继结点,就要往上找,直到有个结点其左分支是由我们这些结点上来的,那这个结点就是后继结点。否则,没有后继结点。

	public static Node getSuccessorNode(Node node) {
		if (node == null) {
			return node;
		}
		//若有右分支树,则后继结点在右分支的最左结点
		if (node.right != null) {
			return getLeftMost(node.right);
		} else {
			//在无右分支的情况,则向上找,直到有个结点其左分支是由我们这些结点上来的。
			// 那个结点就是后继结点,否则没有后继结点
			Node parent = node.parent;
			while (parent != null && parent.left != node) {
				node = parent;
				parent = node.parent;
			}
			return parent;
		}
	}

	public static Node getLeftMost(Node node) {
		if (node == null) {
			return node;
		}
		while (node.left != null) {
			node = node.left;
		}
		return node;
	}

对应情况1对应情况2

二叉树的序列化和反序列化

就是内存里的一棵树如何变成字符串形式,又如何从字符串形式变成内存里的树
如何判断一颗二叉树是不是另一棵二叉树的子树?

折纸问题

请把一段纸条竖着放在桌子上,然后从纸条的下边向上方对折1次,压出折痕后
展开。
此时折痕是凹下去的,即折痕突起的方向指向纸条的背面。
如果从纸条的下边向上方连续对折2次,压出折痕后展开,此时有三条折痕,从
上到下依次是下折痕、下折痕和上折痕。
给定一个输入参数N,代表纸条都从下边向上方连续对折N次。
请从上到下打印所有折痕的方向。
例如:N=1时,打印: down N=2时,打印: down down up

public static void printAllFolds(int N) {
		printProcess(1, N, true);
	}

	public static void printProcess(int i, int N, boolean down) {
		if (i > N) {
			return;
		}
		printProcess(i + 1, N, true);
		System.out.println(down ? "down " : "up ");
		printProcess(i + 1, N, false);
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值