首页 > 编程语言 >代码随想录算法训练营第15天 | 二叉树的层序遍历226. 翻转二叉树 101.对称二叉树

代码随想录算法训练营第15天 | 二叉树的层序遍历226. 翻转二叉树 101.对称二叉树

时间:2023-01-29 17:02:19浏览次数:51  
标签:node 15 随想录 que 二叉树 push NULL root size

102. 二叉树的层序遍历

文章:代码随想录 (programmercarl.com)

视频:讲透二叉树的层序遍历 | 广度优先搜索 | LeetCode:102.二叉树的层序遍历_哔哩哔哩_bilibili

思路:

层序遍历一个二叉树。就是从左到右一层一层的去遍历二叉树。这种遍历的方式和我们之前讲过的都不太一样。

需要借用一个辅助数据结构即队列来实现,队列先进先出,符合一层一层遍历的逻辑,而用栈先进后出适合模拟深度优先遍历也就是递归的逻辑。

而这种层序遍历方式就是图论中的广度优先遍历,只不过我们应用在二叉树上。

使用队列实现二叉树广度优先遍历,动画如下:

102二叉树的层序遍历

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        queue<TreeNode*> que;
		//迭代法
		if (root != NULL)
		{
			que.push(root);
		}
		//定义存放结果的二维数组
		vector<vector<int>> result;

		//队列为空时,循环结束
		while (!que.empty())
		{
			//获取队列长度——每一层的元素个数
			int size = que.size();
			//定义一维数组,存放每一层的元素
			vector<int> vec;
			//第二层循环结束的条件:每一层元素全部弹出时,本层循环结束
			while (size--)
			{
				TreeNode* node = que.front();
				que.pop();
				vec.push_back(node->val);
				//如果弹出元素有子结点时,将子节点加入队列
				if (node->left != NULL)
				{
					que.push(node->left);
				}
				if (node->right != NULL)
				{
					que.push(node->right);
				}
			}
			//循环结束,将一维数组存入二维数组result中
			result.push_back(vec);
		}
		return result;
    }
};

107. 二叉树的层序遍历 II

思路:

相对于102.二叉树的层序遍历,就是最后把result数组反转一下就可以了。

class Solution {
public:
    vector<vector<int>> levelOrderBottom(TreeNode* root) {
        queue<TreeNode*> que;
		if (root != NULL)
		{
			que.push(root);
		}
		vector<vector<int>> result;

		while (!que.empty())
		{
			int size = que.size();
			vector<int> vec;
			while (size--)
			{
				TreeNode* node = que.front();
				que.pop();
				vec.push_back(node->val);

				if (node->left != NULL)
				{
					que.push(node->left);
				}
				if (node->right != NULL)
				{
					que.push(node->right);
				}
			}
			result.push_back(vec);
		}
		reverse(result.begin(), result.end());
		return result;
    }
};

199. 二叉树的右视图

思路:

层序遍历的时候,判断是否遍历到单层的最后面的元素,如果是,就放进result数组中,随后返回result就可以了。

class Solution {
public:
    vector<int> rightSideView(TreeNode* root) {
        queue<TreeNode*> que;
		if (root != NULL)
		{
			que.push(root);
		}
		vector<int> result;

		while (!que.empty())
		{
			int size = que.size();
			while (size--)
			{
				TreeNode* node = que.front();
				que.pop();
				if (size == 0)
				{
					result.push_back(node->val);
				}
				if (node->left != NULL)
				{
					que.push(node->left);
				}
				if (node->right != NULL)
				{
					que.push(node->right);
				}
			}
		}
		return result;
    }
};

637. 二叉树的层平均值

思路:

本题就是层序遍历的时候把一层求个总和在取一个均值

class Solution {
public:
    vector<double> averageOfLevels(TreeNode* root) {
        queue<TreeNode*> que;
		if (root != NULL)
		{
			que.push(root);
		}
		vector<double> result;

		while (!que.empty())
		{
			int size = que.size();
			int size_pro = size;
			double sum = 0;
			while (size--)
			{
				TreeNode* node = que.front();
				que.pop();
				sum += node->val;
				if (node->left != NULL)
				{
					que.push(node->left);
				}
				if (node->right != NULL)
				{
					que.push(node->right);
				}
			}
			result.push_back(sum / size_pro);
		}
		return result;
    }
};

429. N 叉树的层序遍历

思路:

这道题依旧是模板题,只不过一个节点有多个孩子了

二叉树的孩子用node->left,node->right表示

N叉树的孩子用node->children[i]表示

class Solution {
public:
    vector<vector<int>> levelOrder(Node* root) {
        queue<Node*> que;
        if (root != NULL)
        {
            que.push(root);
        }
        vector<vector<int>> result;

        while (!que.empty())
        {
            int size = que.size();
            vector<int> vec;
            while (size--)
            {
                Node* node = que.front();
                que.pop();
                vec.push_back(node->val);
                //N叉树和二叉树的层序遍历只在最后将子节点插入队列中有差异
                for (int i = 0; i < node->children.size(); i++)
                {
                    if (node->children[i] != NULL) 
                    {
                        que.push(node->children[i]);
                    }
                }
            }
            result.push_back(vec);
        }
        return result;
    }
};

515. 在每个树行中找最大值

思路:

层序遍历,取每一层的最大值

class Solution {
public:
    vector<int> largestValues(TreeNode* root) {
        queue<TreeNode*> que;
		if (root != NULL)
		{
			que.push(root);
		}
		vector<int> result;

		while (!que.empty())
		{
			int size = que.size();
			int max = INT_MIN;
			while (size--)
			{
				TreeNode* node = que.front();
				que.pop();
				if (node->val > max)
				{
					max = node->val;
				}
				if (node->left != NULL)
				{
					que.push(node->left);
				}
				if (node->right != NULL)
				{
					que.push(node->right);
				}
			}
			result.push_back(max);
		}
		return result;
    }
};

116. 填充每个节点的下一个右侧节点指针

思路:

本题依然是层序遍历,只不过在单层遍历的时候记录一下本层的头部节点,然后在遍历的时候让前一个节点指向本节点就可以了

116.填充每个节点的下一个右侧节点指针

class Solution {
public:
    Node* connect(Node* root) {
        queue<Node*> que;
        if (root != NULL)
        {
            que.push(root);
        }
        while (!que.empty())
        {
            int size = que.size();
            Node* nodePre;//前驱节点
            Node* node;//当前结点
            for (int i = 0; i < size; i++)
            {
                if (i == 0) //位于本层第一个元素时,头结点既是当前结点,也是前驱节点
                {
                    nodePre = que.front();
                    que.pop();
                    node = nodePre;
                }
                else //不是本层头结点时
                {
                    node = que.front();
                    que.pop();
                    nodePre->next = node; //前驱节点指向当前结点
                    nodePre = nodePre->next; //前驱节点后移一位
                }
                if (node->left != NULL)
                {
                    que.push(node->left);
                }
                if (node->right != NULL)
                {
                    que.push(node->right);
                }
            }
            nodePre->next = NULL; //本层最后一个元素的指针指向NULL
        }
        return root;
    }
};

117. 填充每个节点的下一个右侧节点指针 II

img

思路:

这道题目说是二叉树,但116题目说是完整二叉树,其实没有任何差别,一样的代码一样的逻辑一样的味道

class Solution {
public:
    Node* connect(Node* root) {
        queue<Node*> que;
        if (root != NULL)
        {
            que.push(root);
        }

        while (!que.empty())
        {
            int size = que.size();
            Node* nodePre;
            Node* node;
            for (int i = 0; i < size; i++)
            {
                if (i == 0)
                {
                    nodePre = que.front();
                    que.pop();
                    node = nodePre;
                }
                else 
                {
                    node = que.front();
                    que.pop();
                    nodePre->next = node;
                    nodePre = nodePre->next;
                }
                if (node->left != NULL)
                {
                    que.push(node->left);
                }
                if (node->right != NULL)
                {
                    que.push(node->right);
                }
            }
            nodePre->next = NULL;
        }
        return root;
    }
};

104. 二叉树的最大深度

class Solution {
public:
    int maxDepth(TreeNode* root) {
        if (root == NULL)
		{
			return 0;
		}
		queue<TreeNode*> que;
		que.push(root);
		int depth = 0;

		while (!que.empty())
		{
			int size = que.size();
			while (size--)
			{
				TreeNode* node = que.front();
				que.pop();
				if (node->left != NULL)
				{
					que.push(node->left);
				}
				if (node->right != NULL)
				{
					que.push(node->right);
				}
			}
			depth++;
		}
		return depth;
    }
};

111. 二叉树的最小深度

思路:

需要注意的是,只有当左右孩子都为空的时候,才说明遍历的最低点了。如果其中一个孩子为空则不是最低点

class Solution {
public:
    int minDepth(TreeNode* root) {
        if (root == NULL)
		{
			return 0;
		}
		queue<TreeNode*> que;
		que.push(root);
		int minDepth = 0;

		while (!que.empty())
		{
			int size = que.size();
			minDepth++;
			while (size--)
			{
				TreeNode* node = que.front();
				que.pop();
				if (node->left != NULL)
				{
					que.push(node->left);
				}
				if (node->right != NULL)
				{
					que.push(node->right);
				}
				if (node->left == NULL && node->right == NULL)
				{
					return minDepth;
				}
			}
		}
		return minDepth;
    }
};

226. 翻转二叉树

文章:代码随想录 (programmercarl.com)

视频:听说一位巨佬面Google被拒了,因为没写出翻转二叉树 | LeetCode:226.翻转二叉树_哔哩哔哩_bilibili

思路:

如果要从整个树来看,翻转还真的挺复杂,整个树以中间分割线进行翻转,如图:

注意只要把每一个节点的左右孩子翻转一下,就可以达到整体翻转的效果

226.翻转二叉树1

可以发现想要翻转它,其实就把每一个节点的左右孩子交换一下就可以了。

遍历的过程中去翻转每一个节点的左右孩子就可以达到整体翻转的效果。

注意只要把每一个节点的左右孩子翻转一下,就可以达到整体翻转的效果

这道题目使用前序遍历和后序遍历都可以,唯独中序遍历不方便,因为中序遍历会把某些节点的左右孩子翻转了两次!建议拿纸画一画,就理解了

那么层序遍历可以不可以呢?依然可以的!只要把每一个节点的左右孩子翻转一下的遍历方式都是可以的!

我们下文以前序遍历为例,通过动画来看一下翻转的过程:

翻转二叉树

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        //root不是整个二叉树的根节点,而是当前结点
		if (root == NULL)
		{
			return NULL;
		}
		swap(root->left, root->right);
		invertTree(root->left);
		invertTree(root->right);

		return root;
    }
};

101. 对称二叉树

文章:代码随想录 (programmercarl.com)

视频:新学期要从学习二叉树开始! | LeetCode:101. 对称二叉树_哔哩哔哩_bilibili

思路:

首先想清楚,判断对称二叉树要比较的是哪两个节点,要比较的可不是左右节点!

对于二叉树是否对称,要比较的是根节点的左子树与右子树是不是相互翻转的,理解这一点就知道了其实我们要比较的是两个树(这两个树是根节点的左右子树),所以在递归遍历的过程中,也是要同时遍历两棵树。

那么如何比较呢?

比较的是两个子树的里侧和外侧的元素是否相等。如图所示:

101. 对称二叉树1

那么遍历的顺序应该是什么样的呢?

本题遍历只能是“后序遍历”,因为我们要通过递归函数的返回值来判断两个子树的内侧节点和外侧节点是否相等。

class Solution {
public:
    bool compare(TreeNode* left, TreeNode* right)
	{
		if (left == NULL && right != NULL)
		{
			return false;
		}
		else if (left != NULL && right == NULL){
			return false;
		}
		else if (left == NULL && right == NULL) {
			return true;
		}
		else if (left->val != right->val) {
			return false;
		}
		else {
			bool outside = compare(left->left, right->right);
			bool inside = compare(left->right, right->left);
			return outside && inside;
		}
	}
    bool isSymmetric(TreeNode* root) {
        if (root == NULL) 
		{
			return true;
		}
		return compare(root->left, root->right);
    }
};

标签:node,15,随想录,que,二叉树,push,NULL,root,size
From: https://www.cnblogs.com/chaoyue-400/p/17073144.html

相关文章

  • 23/1/29-LeetCode 15: 3Sum
    LeetCode15:3Sum写过了2sum,现在再来写3sum,虽然大一下数据结构是写过的orz,应该是写过的,但是某人忘得很彻底。。。没事不迟!0.回顾一下2sum在一维array数组里找到两个数......
  • 代码随想录算法训练营day14 | leetcode 层序遍历 226.翻转二叉树 101.对称二叉树 2
    层序遍历/***二叉树的层序遍历*/classQueueTraverse{/***存放一层一层的数据*/publicList<List<Integer>>resList=newArrayList<>()......
  • 力扣---2315. 统计星号
    给你一个字符串s,每两个连续竖线'|'为一对。换言之,第一个和第二个'|'为一对,第三个和第四个'|'为一对,以此类推。请你返回不在竖线对之间,s中'*'的数目。注意......
  • 7.15 SQL Server UNION联合查询(并集)
    SQLServerUNION(并集)目录SQLServerUNION(并集)简介UNION与UNIONALLUNION(联合)与JOIN(联接)示例UNION与ORDERBY示例简介SQLServer联合查询SQLServerUNION是一......
  • 2315. 统计星号
    2315.统计星号题解:按题意模拟classSolution{publicintcountAsterisks(Strings){intn=s.length();intres=0;//是否不在......
  • 手电筒上架亚马逊UL1576测试报告
    一、办理UL测试报告的流程是什么?1、咨询报价2、签订合同3、填写申请表、并将样品和有关技术文件送至机构。5、支付测试费用。6、安排产品进行测试。7、如果试验不合格,机构将......
  • 15年封神,GitHub开发者破亿!
    15年封神,GitHub开发者破亿!投递人 itwriter2 发布于 2023-01-2717:25 评论(0) 有1028人阅读 原文链接 [收藏] « »封神15年,GitHub用户现如今破了1......
  • LeetCode:2315. 统计星号
    题目思路解答classSolution{public:intcountAsterisks(strings){intlength=s.length();intline=0;intnum=0;......
  • 代码随想录算法训练营day13
    基础知识二叉树基础知识二叉树多考察完全二叉树、满二叉树,可以分为链式存储和数组存储,父子兄弟访问方式也有所不同,遍历也分为了前中后序遍历和层次遍历Java定义public......
  • 257. 二叉树的所有路径
    问题描述https://leetcode.cn/problems/binary-tree-paths/description/解题思路叶子结点时,添加到结果序列即可。代码#Definitionforabinarytreenode.#class......