树的层次遍历(Leedcode 102、107、199、103)技巧 --- 队列

前面的话

队列是一种比较特殊的线性结构,是典型的先进先出。它只允许在表的的前端进行删除,在表的后端进行插入。前面说过,树的深度优先遍历可以借助栈来实现,而树的层次遍历可以借助队列来实现。

队列基础使用

java中linkedList提供了方法支持队列的使用,实现了Queue接口

  • 队列的创建: Queue<Integer> queue = new LinkedList<>();//声明队列
  • 添加数据: offer()、add()
  • 删除队首:poll()
  • 查看队首:peek()不删除
题目
题目(102)
给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。

例如:
给定二叉树: [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7
返回其层次遍历结果:
[
  [3],
  [9,20],
  [15,7]
]
解析
  • 根节点入队
  • 大循环开始:得到队列的长度(队列的长度为每一层节点的个数)。
  • for循环队列的长度,每次取出队首节点。建立一个数组list ,存放节点的val值。检查当前节点有没有左右节点,如果有,左右孩子入队。直到for结束。此时lest数组存储了每一层的val,将list添加进最终的result中。
  • 上述大循环直到队列为空,循环结束。
  public List<List<Integer>> levelOrder(TreeNode root) {
     LinkedList<List<Integer>> res = new LinkedList<>();
		 if (root == null) {
			  return res;
		  }
		 Queue<TreeNode> queue = new LinkedList<>(); 
		 queue.offer(root); // 添加根节点
		 while(!queue.isEmpty()) {
		     // 创建一个list,用于添加每一层的val
			 List<Integer> levelList = new ArrayList<Integer>();
			 int count = queue.size(); // 每一层的长度
			  for(int i = 0; i < count;i++ ) {
				  TreeNode node = queue.poll();
				  levelList.add(node.val);
				  if(node.left != null) {
					  queue.offer(node.left);
				  }
				  if(node.right != null) {
					  queue.offer(node.right);
				  }
			  }
			  res.add(levelList);
		 }
		 
		return res;     
	 }
题目 (107)
给定一个二叉树,返回其节点值自底向上的层次遍历。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)

例如:
给定二叉树 [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7
返回其自底向上的层次遍历为:
[
  [15,7],
  [9,20],
  [3]
]
解析

这一题与上面的题目,只是结果返回的顺序不一样。我们只需要将每次for循环结束后,res倒序添加levellist就行。

res.add(levelList)改为res.addFrist(levelList),倒序添加就行。

题目 (199)
给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。

示例:
输入: [1,2,3,null,5,null,4]
输出: [1, 3, 4]
解释:

   1            <---
 /   \
2     3         <---
 \     \
  5     4       <---
解析:

这题不一样的地方是,我们只需要将每一层最后一个数添加到res数组中。

稍作修改:

我们不需要在每一个for 循环中创建一个list来存储每一层的val值,只需要在每一次for循环结束时,将最后一个节点的val值添加到结果res中。

 public List<Integer> rightSideView(TreeNode root) {
            List<Integer> res = new ArrayList<>();
		 if (root == null) {
			  return res;
		  }
		 Queue<TreeNode> queue = new LinkedList<>(); 
		 queue.offer(root);
		 while(!queue.isEmpty()) {
			 int count = queue.size(); // 每一层的长度
			  for(int i = 0; i < count;i++ ) {
				  TreeNode node = queue.poll();
				  
				  if(node.left != null) {
					  queue.offer(node.left);
				  }
				  if(node.right != null) {
					  queue.offer(node.right);
				  }
				  if(i== count-1) {
					  res.add(node.val);
				  }
			  }
			  
		 }
		 
		return res;   
    }
题目 (103)
给定一个二叉树,返回其节点值的锯齿形层次遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。

例如:
给定二叉树 [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7
返回锯齿形层次遍历如下:

[
  [3],
  [20,9],
  [15,7]
]
解析
方法一:使用队列

这题前面不同的是,偶数层都要倒过来输出。很容易想到,我们设置一个flag来辨别奇偶行。如果是奇数行,每一个for循环建立的list数组向后添加val值;如果是偶数行,那么for循环中的list数组向前添加val值。

稍作修改:

	// 偶数层,从前面添加				 
	if(flag % 2 == 0) {
		levelList.add(0, node.val);	 
	}else {
		levelList.add(node.val);
   }
方法二:双栈交替
  • 创建两个栈 stack1stack2(奇偶栈)。分别存储奇偶层的节点
  • 根元素入栈 stack1
  • 循环取出stack1的栈顶节点,并将其val添加到数组level1中,如果该节点存在左右节点,将其放入stack2中。直到stack1为空,并将level1添加到res中。
  • stack1为空了,stack2有节点,循环取出stack2的栈顶节点,并将其val添加到数组level2中,如果该节点存在左右节点,将其放入stack1中。直到stack2为空。
  • 两栈交替。直到两栈都为空,并将level2添加到res中。
  • 返回res
 // 方法二:  双栈交替
	public List<List<Integer>> zigzagLevelOrder2(TreeNode root) {
		List<List<Integer>> res = new ArrayList<>();
		if(root == null) {
			 return res;
		 }
		// 存放奇数层的栈
		Stack<TreeNode> stack1 = new Stack<>();
		// 存放偶数层的栈
		Stack<TreeNode> stack2 = new Stack<>();
		stack1.push(root);
		while(!stack1.isEmpty() || !stack2.isEmpty()) {
			// 两栈交替
			if(!stack1.isEmpty()) {
				while(!stack1.isEmpty()) {
					List<Integer> level1 = new ArrayList<>();
					int num1 = stack1.size();
					for(int i = 0;i<num1;i++) {
						TreeNode node1 = stack1.pop();
						level1.add(node1.val);
						// 偶数层,先left节点入栈
						if(node1.left != null) {
							stack2.push(node1.left);
						}
						if(node1.right != null) {
							stack2.push(node1.right);
						}
						
					}
					res.add(level1);
				}
			}else {
				while(!stack2.isEmpty()) {
					// 奇数层,先right节点入栈
					List<Integer> level2 = new ArrayList<>();
					int num2 = stack2.size();
					for(int i = 0;i<num2;i++) {
						TreeNode node2 = stack2.pop();
						level2.add(node2.val);
						
						if(node2.right != null) {
							stack1.push(node2.right);
						}
						if(node2.left != null) {
							stack1.push(node2.left);
						}
					}
				   res.add(level2);
				}
			}
		}
		return res;	
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值