在此非常感谢“代码随想录”的通俗易懂的总结,昨天一口气打了六个,感觉意犹未尽,今天继续打,怎么说,先凑10个吧!
(致敬叶师傅和李小龙)
“我不害怕曾经练过一万种踢法的人,但我害怕一种踢法练过一万次的人”(by 叶师傅的徒弟Bruce Lee)
今天是2021年3月15日,昨天龙抬头和白色情人节的“双节”刚刚过去,第一次一口气刷了6道中等难度Leetcode题。今天又迎来了“3.15——国际消费者权益日”,那就今天继续再打4道,怎么说都要先凑齐10个!加油,冲冲冲!
简单问题可以不简单,正如李小龙所说,把一件简单事情做到极致,把每一道刷透理解透,注重质量,让自己变得无可替代,是一件非常不简单的事情!
这道题目背后有一个让程序员心酸的故事,据说谷歌90%的工程师使用的软件Homebrew的作者Max Howell,就是因为面试谷歌时没有在白板上写出翻转二叉树这道题,最后被Google拒绝了。
「这道题目使用前序遍历、后序遍历以及层序遍历都可以,但只是使用单纯中序遍历不行,因为中序遍历会把某些节点的左右孩子翻转了两次,但是可以把中序遍历稍微改动一下即可!」
方法一、广度优先遍历——层序遍历
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
queue<TreeNode*> que;
if(root) que.push(root);
while(!que.empty()){
int size=que.size();
for(int i=0;i<size;++i){
TreeNode* cur=que.front();
que.pop();
swap(cur->left,cur->right);
if(cur->left) que.push(cur->left);
if(cur->right) que.push(cur->right);
}
}
return root;
}
};
方法二、深度优先遍历——前序遍历(递归)
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
if(root==NULL) return root;
swap(root->left,root->right);//中
invertTree(root->left);//左
invertTree(root->right);//右
return root;
}
};
方法三、深度优先遍历——后序遍历(迭代)
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
// if(root==NULL) return root;
stack<TreeNode*> st;
if(root) st.push(root);
while(!st.empty()){
TreeNode* cur=st.top();//中
st.pop();
swap(cur->left,cur->right);
if(cur->right) st.push(cur->right);//右
if(cur->left) st.push(cur->left);//左
}
return root;
}
};
方法四、中序遍历递归改编版
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
if (root == NULL) return root;
invertTree(root->left); // 左
swap(root->left, root->right); // 中
invertTree(root->left); // 注意 这里依然要遍历左孩子,因为中间节点已经翻转了
return root;
}
};
题目描述:
给定一个 N 叉树,返回其节点值的前序遍历 。
N叉树在输入中按层序遍历进行序列化表示,每组子节点由空值 null 分隔(请参见示例)。
进阶:
递归法很简单,你可以使用迭代法完成此题吗?
示例 1:
输入:root = [1,null,3,2,4,null,5,6]
输出:[1,3,5,6,2,4]
示例 2:
输入:root = [1,null,2,3,4,5,null,null,6,7,null,8,null,9,10,null,null,11,null,12,null,13,null,null,14]
输出:[1,2,3,6,7,11,14,4,8,12,5,9,13,10]
方法一、递归解法
class Solution {
public:
vector<int> result;
void traversal(Node* root){
if(root==NULL) return;
result.push_back(root->val);
int size=root->children.size();
for(int i=0;i<size;++i){
traversal(root->children[i]);
}
}
vector<int> preorder(Node* root) {
traversal(root);
return result;
}
};
方法二、迭代解法
class Solution {
public:
vector<int> preorder(Node* root) {
vector<int> result;
if(root==NULL) return result;
stack<Node*> st;
st.push(root);
while(!st.empty()){
Node* cur=st.top();
st.pop();
result.push_back(cur->val);
int size=cur->children.size();
for(int i=size-1;i>=0;--i){
if(cur->children[i]) st.push(cur->children[i]);
}
}
return result;
}
};
题目描述:
给定一个 N 叉树,返回其节点值的后序遍历 。
N叉树在输入中按层序遍历进行序列化表示,每组子节点由空值 null 分隔(请参见示例)。
进阶:
递归法很简单,你可以使用迭代法完成此题吗?
输入:root = [1,null,3,2,4,null,5,6]
输出:[5,6,3,2,4,1]
示例 2:
输入:root = [1,null,2,3,4,5,null,null,6,7,null,8,null,9,10,null,null,11,null,12,null,13,null,null,14]
输出:[2,6,14,11,7,3,12,8,4,13,9,10,5,1]
方法一、递归方法
class Solution {
public:
vector<int> result;
void traversal(Node* root){
if(root==NULL) return;
int size=root->children.size();
for(int i=0;i<size;++i){
traversal(root->children[i]);
}
result.push_back(root->val);
}
vector<int> postorder(Node* root) {
traversal(root);
return result;
}
};
方法二、迭代方法
class Solution {
public:
vector<int> postorder(Node* root) {
vector<int> result;
if(root==NULL) return result;
stack<Node*> st;
st.push(root);
while(!st.empty()){
Node* cur=st.top();
st.pop();
result.push_back(cur->val);
int size=cur->children.size();
for(int i=0;i<size;++i){
st.push(cur->children[i]);
}
}
reverse(result.begin(),result.end());
return result;
}
};
题目描述:
给定一个二叉树,检查它是否是镜像对称的。
进阶:
你可以运用递归和迭代两种方法解决这个问题吗?
用三种方法刷透就完事!(当然队列和栈只是容器不同,而原理都是迭代!)
方法一、递归方法
class Solution {
public:
bool compare(TreeNode* left,TreeNode* right){
if(!left && !right) return true;//排除根左右全是空节点情况
else if(!left || !right ||left->val!=right->val) return false;
else return (compare(left->right,right->left) && compare(left->left,right->right));
}
bool isSymmetric(TreeNode* root) {
if(!root) return true;
else return compare(root->left,root->right);
}
};
方法二、迭代之队列方法
引用一下代码随想录的动图便于理解:
class Solution {
public:
bool isSymmetric(TreeNode* root) {
if(!root) return true;
queue<TreeNode*> que;
que.push(root->left);
que.push(root->right);
while(!que.empty()){
TreeNode* left=que.front();
que.pop();
TreeNode* right=que.front();
que.pop();
if(!left && !right) continue;
else if(!left || !right || left->val!=right->val) return false;
else{
que.push(left->left);
que.push(right->right);
que.push(left->right);
que.push(right->left);
}
}
return true;
}
};
方法三、迭代之栈方法
class Solution {
public:
bool isSymmetric(TreeNode* root) {
if(!root) return true;
stack<TreeNode*> st;
st.push(root->right);
st.push(root->left);
while(!st.empty()){
TreeNode* left=st.top();
st.pop();
TreeNode* right=st.top();
st.pop();
if(!left && !right) continue;
else if(!left || !right || left->val!=right->val) return false;
else{
st.push(left->left);
st.push(right->right);
st.push(left->right);
st.push(right->left);
}
}
return true;
}
};
代码随想录链接
二叉树
针对二叉树的问题,解题之前一定要想清楚究竟是前中后序遍历,还是层序遍历。
「二叉树解题的大忌就是自己稀里糊涂的过了,但是也不知道自己是怎么遍历的。」
对于二叉树节点的定义,C++代码如下:
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
对于这个定义中TreeNode(int x) : val(x), left(NULL), right(NULL) {} 这一行我开始也有些不太懂,后来才知道这是构造函数。
构造函数也可以不写,但是new一个新的节点的时候就比较麻烦。
例如有构造函数,定义初始值为9的节点:
TreeNode* a = new TreeNode(9);
没有构造函数的话就要这么写:(非常麻烦不方便!)
TreeNode* a = new TreeNode();
a->val = 9;
a->left = NULL;
a->right = NULL;
欢迎大家扫码关注本人公众号:编程复盘与思考随笔
(关注后可以免费获得本人在csdn发布的资源源码)