目录
二叉树
深度优先遍历
class Solution {
public:
TreeNode* mirrorTree(TreeNode* root) {
if(root == NULL) { return NULL; }
//swap(root->left, root->right);
TreeNode* left = mirrorTree(root->left);
TreeNode* right = mirrorTree(root->right);
root->left = right;
root->right = left;
//swap(root->left, root->right);
return root;
}
};
二叉树的周游(递归实现)(√)
以⼀种特定的规律访问树中的所有节点。常见的周游⽅式包括:
前序周游(Pre-order traversal):访问根结点;按前序周游左⼦树;按前序周游
右⼦树。
中序周游(In-order traversal):按中序周游左⼦树;访问根结点;按中序周游右
⼦树。特别地,对于⼆叉搜索树⽽⾔,中序周游可以获得⼀个由⼩到⼤或者由⼤
到⼩的有序序列。
后续周游(Post-order traversal):按后序周游左⼦树;按后序周游右⼦树;访问
根结点。
DFS
三种周游⽅式都是深度优先算法(depth-first search)
深度优先算法最⾃然的实现⽅式是通过递归实现,事实上,⼤部分树相关的⾯试问题都可以优先考虑递归。
深度优先的算法往往都可以通过使⽤栈数据结构将递归化为⾮递归实现。
144. 二叉树的前序遍历
94. 二叉树的中序遍历
145. 二叉树的后序遍历
class Solution {
private:
void postorderHelper(TreeNode* cur, vector<int>& ans)
{
if(cur == nullptr) { return; }
postorderHelper(cur->left, ans);
postorderHelper(cur->right, ans);
result.push_back(cur->val);
}
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> result;
postorderHelper(root, result);
return result;
}
};
N叉树的周游(递归实现)(√)
589. N 叉树的前序遍历
590. N 叉树的后序遍历
class Solution {
private:
void preorderHelper(Node* cur, vector<int>& ans)
{
if(cur == nullptr) { return; }
ans.push_back(cur->val); // N 叉树的前序遍历
for(int i=0; i<cur->children.size(); ++i)
{
preorderHelper(cur->children[i], ans);
}
//ans.push_back(cur->val); // N 叉树的后序遍历
}
public:
vector<int> preorder(Node* root) {
vector<int> result;
preorderHelper(root, result);
return result;
}
};
二叉树的周游(迭代实现)(√)
145. 二叉树的后序遍历
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> result;
if(root == nullptr) { return result; }
stack<TreeNode*> s;
s.push(root);
while(!s.empty())
{
TreeNode* node = s.top(); s.pop();
result.push_back(node->val);
if(node->left) s.push(node->left);
if(node->right) s.push(node->right);
}
reverse(result.begin(), result.end()); //注意这里以及入栈顺序
return result;
}
};
中序遍历迭代重点看一下。没理解透彻。
94. 二叉树的中序遍历
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> result;
if(root == nullptr) { return result; }
stack<TreeNode*> s;
TreeNode* cur = root;
while(cur != nullptr || !s.empty())
{
if(cur != nullptr) // 指针来访问节点,访问到最底层
{
s.push(cur); // 将访问的节点放进栈
cur = cur->left; // 左
}
else
{
cur = s.top(); // 从栈里弹出的数据,就是要处理的数据(放进result数组里的数据)
s.pop();
result.push_back(cur->val); // 中
cur = cur->right; // 右
}
}
return result;
}
};
广度优先遍历
层次周游(√)
层次周游(Level traversal):⾸先访问第0层,也就是根结点所在的层;当第i层的所有结点访问完之后,再从左⾄右依次访问第i+1层的各个结点。
层次周游属于⼴度优先算法(breadth-first search)。
199.二叉树的右视图
637.二叉树的层平均值
429.N叉树的前序遍历
515.在每个树行中找最大值
104.二叉树的最大深度
111.二叉树的最小深度
116.填充每个节点的下一个右侧节点指针(没仔细看)
117.填充每个节点的下一个右侧节点指针II(没仔细看)
102. 二叉树的层序遍历
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> result;
if(root == nullptr) { return result; }
queue<TreeNode*> q;
q.push(root);
while(!q.empty())
{
int currentLevelSize = q.size();
result.push_back(vector<int> ());
for(int i=0; i<currentLevelSize; ++i)
{
auto node = q.front(); q.pop();
result.back().push_back(node->val);
if(node->left) { q.push(node->left); }
if(node->right) { q.push(node->right); }
}
}
// 107. 二叉树的层序遍历 II levelOrderBottom
// 只需加如下一行代码即可
//reverse(result.begin(), result.end());
return result;
}
};
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> result;
if(root == nullptr) { return result; }
queue<TreeNode*> q;
q.push(root);
while(!q.empty())
{
int currentSize = q.size();
vector<int> vec;
for(int i=0; i<currentSize; ++i)
{
TreeNode* node = q.front(); q.pop();
vec.push_back(node->val);
if(node->left) { q.push(node->left); }
if(node->right) { q.push(node->right); }
}
result.push_back(vec);
}
return result;
}
};
107. 二叉树的层序遍历 II
429. N 叉树的层序遍历
class Solution {
public:
vector<vector<int>> levelOrder(Node* root) {
vector<vector<int>> result;
if(root == nullptr) { return result; }
queue<Node*> q;
q.push(root);
while(!q.empty())
{
int currentSize = q.size();
vector<int> vec;
for(int i=0; i<currentSize; ++i)
{
Node* node = q.front(); q.pop();
vec.push_back(node->val);
for(int j=0; j<node->children.size(); ++j)
{
if(node->children[j]) { q.push(node->children[j]); }
}
}
result.push_back(vec);
}
return result;
}
};
199. 二叉树的右视图
class Solution {
public:
vector<int> rightSideView(TreeNode* root) {
vector<int> result;
if(root == nullptr) { return result; }
queue<TreeNode*> q;
q.push(root);
while(!q.empty())
{
int currentSize = q.size();
for(int i=0; i<currentSize; ++i)
{
TreeNode* node = q.front(); q.pop();
if(i == currentSize-1) { result.push_back(node->val); }
if(node->left) { q.push(node->left); }
if(node->right) { q.push(node->right); }
}
}
return result;
}
};
637. 二叉树的层平均值
class Solution {
public:
vector<double> averageOfLevels(TreeNode* root) {
vector<double> result;
if(root == nullptr) { return result; }
queue<TreeNode*> q;
q.push(root);
while(!q.empty())
{
int currentSize = q.size();
double sum = 0;
for(int i=0; i<currentSize; ++i)
{
TreeNode* node = q.front(); q.pop();
sum += node->val;
if(node->left) { q.push(node->left); }
if(node->right) { q.push(node->right); }
}
result.push_back(sum / currentSize);
}
return result;
}
};
515. 在每个树行中找最大值
class Solution {
public:
vector<int> largestValues(TreeNode* root) {
vector<int> result;
if(root == nullptr) { return result; }
queue<TreeNode*> q;
q.push(root);
while(!q.empty())
{
int currentLevelSize = q.size();
int maxValue = INT_MIN;
for(int i=0; i<currentLevelSize; ++i)
{
auto node = q.front(); q.pop();
maxValue = node->val > maxValue ? node->val : maxValue;
if(node->left) { q.push(node->left); }
if(node->right) { q.push(node->right); }
}
result.push_back(maxValue);
}
return result;
}
};
116. 填充每个节点的下一个右侧节点指针
class Solution {
public:
Node* connect(Node* root) {
if(root == nullptr) { return nullptr; }
queue<Node*> q;
q.push(root);
while(!q.empty())
{
int currentLevelSize = q.size();
Node* nodePre;
Node* node;
for(int i=0; i<currentLevelSize; ++i)
{
if(i == 0)
{
nodePre = q.front(); q.pop();
node = nodePre;
}
else
{
node = q.front(); q.pop();
nodePre->next = node;
nodePre = nodePre->next;
}
if(node->left) { q.push(node->left); }
if(node->right) { q.push(node->right); }
}
nodePre->next = nullptr;
}
return root;
}
};
117. 填充每个节点的下一个右侧节点指针 II(代码如上)
// An highlighted block
var foo = 'bar';
513. 找树左下角的值
class Solution {
public:
int findBottomLeftValue(TreeNode* root) {
if(root == nullptr) { return 0; }
int result;
queue<TreeNode*> q;
q.push(root);
while(!q.empty())
{
int currentSize = q.size();
for(int i=0; i<currentSize; ++i)
{
TreeNode* node = q.front(); q.pop();
if(i == 0) result = node->val;
if(node->left) q.push(node->left);
if(node->right) q.push(node->right);
}
}
return result;
}
};
104. 二叉树的最大深度(递归实现)
链接: 104. 二叉树的最大深度.
class Solution {
public:
int getdepth(TreeNode* node)
{
if(node == nullptr) { return 0; }
int leftdepth = getdepth(node->left);
int rightdepth = getdepth(node->right);
return max(leftdepth, rightdepth) + 1;
}
int maxDepth(TreeNode* root) {
if(root == nullptr) { return 0; }
return getdepth(root);
}
};
class Solution {
public:
int maxDepth(TreeNode* root) {
if(root == nullptr) { return 0; }
return max(maxDepth(root->left), maxDepth(root->right)) + 1;
}
};
104. 二叉树的最大深度(迭代实现)
class Solution {
public:
int maxDepth(TreeNode* root) {
if(root == nullptr) { return 0; }
int result = 0;
//return max(maxDepth(root->left), maxDepth(root->right)) + 1;
queue<TreeNode*> q;
q.push(root);
while(!q.empty())
{
int currentLevelSize = q.size();
result++;
for(int i=0; i<currentLevelSize; ++i)
{
auto node = q.front(); q.pop();
if(node->left) { q.push(node->left); }
if(node->right) { q.push(node->right); }
}
}
return result;
}
};
559. N 叉树的最大深度
class Solution {
public:
int maxDepth(Node* root) {
if(root == nullptr) { return 0; }
int depth = 0;
queue<Node*> q;
q.push(root);
while(!q.empty())
{
int currentSize = q.size();
depth++;
for(int i=0; i<currentSize; ++i)
{
Node* node = q.front(); q.pop();
for(int j=0; j<node->children.size(); ++j)
{
if(node->children[j]) { q.push(node->children[j]); }
}
}
}
return depth;
}
};
111. 二叉树的最小深度
class Solution {
public:
int getdepth(TreeNode* node)
{
if(node == nullptr) { return 0; }
int leftdepth = getdepth(node->left);
int rightdepth = getdepth(node->right);
if(node->left == nullptr && node->right != nullptr) { return 1 + rightdepth; }
if(node->right == nullptr && node->left != nullptr) { return 1 + leftdepth; }
return 1 + min(leftdepth, rightdepth);
}
int minDepth(TreeNode* root) {
if(root == nullptr) { return 0; }
return getdepth(root);
}
};
class Solution {
public:
int minDepth(TreeNode* root) {
if (root == NULL) return 0;
int depth = 0;
queue<TreeNode*> que;
que.push(root);
while(!que.empty()) {
int size = que.size();
depth++; // 记录最小深度
for (int i = 0; i < size; i++) {
TreeNode* node = que.front();
que.pop();
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
if (!node->left && !node->right) { // 当左右孩子都为空的时候,说明是最低点的一层了,退出
return depth;
}
}
}
return depth;
}
};
222. 完全二叉树的节点个数(×)
class Solution {
public:
int countNodes(TreeNode* root) {
if(root == nullptr) { return 0; }
TreeNode* left = root->left;
TreeNode* right = root->right;
int leftHeight = 0, rightHeight = 0;
while(left) { left = left->left; leftHeight++; }
while(right) { right = right->right; rightHeight++; }
if(leftHeight == rightHeight) { return (2 << leftHeight) - 1; }
return countNodes(root->left) + countNodes(root->right) + 1;
}
};
二叉树的镜像(√)
226. 翻转二叉树(递归版本)
剑指 Offer 27. 二叉树的镜像(代码一样)
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
if(root == nullptr) { return nullptr; }
swap(root->left, root->right); // 前序遍历
if(root->left) { invertTree(root->left); }
if(root->right) { invertTree(root->right); }
//swap(root->left, root->right); // 后序遍历均可
return root;
}
};
平衡二叉树
110. 平衡二叉树
链接: 110. 平衡二叉树.
class Solution {
public:
int level(TreeNode* root)
{
if (root == nullptr) { return 0; }
return max(level(root->left), level(root->right)) + 1;
}
bool isBalanced(TreeNode* root) {
if (root == nullptr) { return true; }
int factor = abs(level(root->left) - level(root->right));
return factor < 2 && isBalanced(root->right) && isBalanced(root->left);
}
};
更好的实现?
⼀种改进⽅式是,可以考虑利⽤动态规划的思想,将TreeNode指针作为key,⾼度作为value,⼀旦发现节点已经被计算过,直接返回结果,这样,level函数对每个节点只计算⼀次。
另⼀种更为巧妙的⽅法是,isBalanced返回当前节点的⾼度,⽤-1表⽰树不平衡。 将计算结果⾃底向上地传递,并且确保每个节点只被计算⼀次,复杂度O(n)。
class Solution {
public:
int level(TreeNode* root)
{
if (root == nullptr) { return 0; }
int leftLevel = level(root->left);
int rightLevel = level(root->right);
if(leftLevel == -1 || rightLevel == -1 || abs(leftLevel - rightLevel) > 1)
{
return -1;
}
return max(leftLevel, rightLevel) + 1;
}
bool isBalanced(TreeNode* root) {
if (root == nullptr) { return true; }
return level(root) >= 0;
}
};
572. 另一棵树的子树
链接: 572. 另一棵树的子树.
Subtree
Tree1 and Tree2 are both binary trees nodes having value, determine if Tree2 is a subtree of Tree1.
class Solution {
public:
bool isSubtree(TreeNode* root, TreeNode* subRoot) {
if(subRoot == nullptr) { return true; }
if(root == nullptr) { return false; }
if(root->val == subRoot->val)
{
if(matchTree(root, subRoot)) { return true; }
}
return isSubtree(root->left, subRoot) || isSubtree(root->right, subRoot);
}
bool matchTree(TreeNode* root, TreeNode* subRoot)
{
if(root == nullptr && subRoot == nullptr) { return true; }
if(root == nullptr || subRoot == nullptr) { return false; }
if(root->val != subRoot->val) { return false; }
return matchTree(root->left, subRoot->left) &&
matchTree(root->right, subRoot->right);
}
};
257. 二叉树的所有路径
class Solution {
public:
void traversal(TreeNode* cur, vector<int>& path, vector<string>& result)
{
path.push_back(cur->val);
// 遇到叶子节点
if(cur->left == nullptr && cur->right == nullptr)
{
string sPath;
// 将path里记录的路径转为string格式
for(int i=0; i<path.size()-1; ++i)
{
sPath += to_string(path[i]);
sPath += "->";
}
sPath += to_string(path[path.size()-1]);
result.push_back(sPath);
return;
}
if(cur->left)
{
traversal(cur->left, path, result);
path.pop_back(); // 回溯
}
if(cur->right)
{
traversal(cur->right, path, result);
path.pop_back(); // 回溯
}
}
vector<string> binaryTreePaths(TreeNode* root) {
vector<string> result;
vector<int> path;
if(root == nullptr) { return result; }
traversal(root, path, result);
return result;
}
};
二叉树的递归
404. 左叶子之和(√)
class Solution {
public:
int sumOfLeftLeaves(TreeNode* root) {
if(root == nullptr) { return 0; }
int leftValue = sumOfLeftLeaves(root->left); //
int rightValue = sumOfLeftLeaves(root->right);
int midValue = 0;
if(root->left && !root->left->left && !root->left->right)
{
midValue = root->left->val;
}
return midValue + leftValue + rightValue;
}
};
112. 路径总和
class Solution {
public:
bool traversal(TreeNode* cur, int count)
{
// 遇到叶子节点,并且计数为0
if(!cur->left && !cur->right && count == 0) { return true; }
// 遇到叶子节点直接返回
if(!cur->left && !cur->right) { return false; }
if(cur->left) { if(traversal(cur->left, count - cur->left->val)) return true; }
if(cur->right) { if(traversal(cur->right, count - cur->right->val)) return true; }
return false;
}
bool hasPathSum(TreeNode* root, int targetSum) {
if(root == nullptr) { return false; }
return traversal(root, targetSum - root->val);
}
};
113. 路径总和 II(未研究carl—重点)
链接: 113. 路径总和 II.
class Solution {
public:
void pathSumHelper(vector<int> path, vector<vector<int>>& answer, TreeNode* root, int targetSum)
{
if(root == nullptr) { return; }
path.push_back(root->val);
if(root->left == nullptr && root->right == nullptr && root->val == targetSum)
{
answer.push_back(path);
}
pathSumHelper(path, answer, root->left, targetSum - root->val);
pathSumHelper(path, answer, root->right, targetSum - root->val);
path.pop_back();
}
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
vector<int> path;
vector<vector<int>> result;
pathSumHelper(path, result, root, targetSum);
return result;
}
};
carl:
class Solution {
private:
vector<int> path;
vector<vector<int>> result;
void pathSumHelper(TreeNode* cur, int count)
{
if(!cur->left && !cur->right && count == 0) { result.push_back(path); return; }
if(!cur->left && !cur->right) { return; }
if(cur->left)
{
path.push_back(cur->left->val);
pathSumHelper(cur->left, count - cur->left->val);
path.pop_back();
}
if(cur->right)
{
path.push_back(cur->right->val);
pathSumHelper(cur->right, count - cur->right->val);
path.pop_back();
}
return;
}
public:
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
result.clear();
path.clear();
if(root == nullptr) { return result; }
path.push_back(root->val);
pathSumHelper(root, targetSum - root->val);
return result;
}
};
437. 路径总和 III
未通过,需要再思考以下。
class Solution {
public:
void pathSumHelper(vector<int> path, vector<vector<int>>& answer, TreeNode* root, int targetSum)
{
if(root == nullptr) { return; }
path.push_back(root->val);
if(root->val == targetSum)
{
answer.push_back(path);
}
pathSumHelper(path, answer, root->left, targetSum - root->val);
pathSumHelper(path, answer, root->right, targetSum - root->val);
}
int pathSum(TreeNode* root, int targetSum) {
vector<int> path;
vector<vector<int>> result;
pathSumHelper(path, result, root, targetSum);
return result.size();
}
};
Tree 与其他数据结构转换
这类题⽬要求将树的结构转化成其他数据结构,例如linked list, array
等,或者反之,从array等结构构成⼀棵树。前者通常是通过树的周游,合并局部解来得到全局解,⽽后者则可以利⽤D&C的策略,递归将数据结构的两部分分别转换成⼦树,再合并。
108. 将有序数组转换为二叉搜索树
链接: 108. 将有序数组转换为二叉搜索树.
多种解法:注意归纳。
方法一:中序遍历,总是选择中间位置左边的数字作为根节点
方法二:中序遍历,总是选择中间位置右边的数字作为根节点
方法三:中序遍历,选择任意一个中间位置数字作为根节点
class Solution {
public:
TreeNode* helper(vector<int>&nums, int first, int last)
{
if(first > last) { return nullptr; }
// 总是选择中间位置左边的数字作为根节点
int mid = (first + last) / 2;
// 总是选择中间位置右边的数字作为根节点
//int mid = (first + last + 1) / 2;
// 选择任意一个中间位置数字作为根节点
//int mid = (first + last + rand() % 2) / 2;
TreeNode* parent = new TreeNode(nums[mid]);
parent->left = helper(nums, first, mid-1);
parent->right = helper(nums, mid+1, last);
return parent;
}
TreeNode* sortedArrayToBST(vector<int>& nums) {
if(nums.size() == 0) { return nullptr; }
if(nums.size() == 1)
{
TreeNode* parent = new TreeNode(nums[0]);
return parent;
}
return helper(nums, 0, nums.size() - 1);
}
};
class Solution {
private:
TreeNode* traversal(vector<int>& nums, int left, int right)
{
if(left > right) { return nullptr; }
int mid = left + (right - left) / 2;
TreeNode* root = new TreeNode(nums[mid]);
root->left = traversal(nums, left, mid - 1);
root->right = traversal(nums, mid + 1, right);
return root;
}
public:
TreeNode* sortedArrayToBST(vector<int>& nums) {
TreeNode* root = traversal(nums, 0, nums.size() - 1);
return root;
}
};
``
### 寻找特定节点
此类题⽬通常会传⼊⼀个当前节点,要求找到与此节点具有⼀定关系的特定节点:例如前驱,后继,左/右兄弟等。了解⼀下常见特定节点的定义及性质。在存在指向⽗节点指针的情况下,通常可以由当前节点出发,向上倒推解决。如果节点没有⽗节点指针,⼀般需要从根节点出发向下搜索,搜索的过程就是DFS。
#### 二叉搜索树中的中序后继
剑指 Offer II 053. 二叉搜索树中的中序后继
链接: [二叉搜索树中的中序后继](https://leetcode-cn.com/problems/P5rCT8/).
```javascript
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* leftMostNode(TreeNode* node)
{
if(node == NULL) { return NULL; }
while(node->left) { node = node->left; }
return node;
}
TreeNode* inorderSuccessor(TreeNode* root, TreeNode* p) {
if(root == NULL || p == NULL) { return NULL; }
if(p->right) { return leftMostNode(p->right); }
TreeNode* successor = NULL;
while(root)
{
if(root->val > p->val)
{
successor = root;
root = root->left;
}
else
{
root = root->right;
}
}
return successor;
}
};
Lowest Common Ancestor(LCA)
Given a binary tree and two nodes. Find the lowest common ancestor of the two nodes in the tree.
For example, the LCA of D & E is B.
235. 二叉搜索树的最近公共祖先
链接: 235. 二叉搜索树的最近公共祖先.
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
bool covers(TreeNode* root, TreeNode* p)
{
if(root == NULL) { return false; }
if(p == root) { return true; }
return covers(root->left, p) || covers(root->right, p);
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
// bottom to top
/*
// return either p or q or NULL
if(root == NULL || root == p || root == q)
{
return root;
}
TreeNode* left = lowestCommonAncestor(root->left, p, q);
TreeNode* right = lowestCommonAncestor(root->right, p, q);
// p and q are on both sides
if((left != NULL) && (right != NULL))
{
return root;
}
// either left or right or NULL
return (left != NULL) ? left : right;
*/
if(covers(root->left, p) && covers(root->left, q))
{
return lowestCommonAncestor(root->left, q, p);
}
if(covers(root->right, p) && covers(root->right, q))
{
return lowestCommonAncestor(root->right, q, p);
}
return root;
}
};
二叉搜索树
700. 二叉搜索树中的搜索(递归版本 / 迭代版本)(×)
class Solution {
public:
TreeNode* searchBST(TreeNode* root, int val) {
if(root == nullptr || root->val == val) { return root; }
if(root->val > val) return searchBST(root->left, val);
if(root->val < val) return searchBST(root->right, val);
return nullptr;
}
};
class Solution {
public:
TreeNode* searchBST(TreeNode* root, int val) {
while (root != NULL) {
if (root->val > val) root = root->left;
else if (root->val < val) root = root->right;
else return root;
}
return NULL;
}
};
98. 验证二叉搜索树(√)
链接: 98. 验证二叉搜索树.
⼀个⼩技巧是:可以同时传⼊最⼩/最⼤值,并且将初始值设为LONG_MIN,LONG_MAX,这样,其左⼦树所有节点的值必须在 LONG_MIN及根节点的值之间,其右⼦树所有节点的值必须在根节点的值以及LONG_MAX之间。
class Solution {
public:
bool helper(TreeNode* root, long long min, long long max)
{
if(root == nullptr) { return true; }
if((root->val < max || (root->val == LONG_MAX && root->right == nullptr)) &&
(root->val > min || (root->val == LONG_MIN && root->left == nullptr)) &&
helper(root->left, min, root->val) &&
helper(root->right, root->val, max))
return true;
return false;
}
bool isValidBST(TreeNode* root) {
return helper(root, LONG_MIN, LONG_MAX);
}
};
Carl:
class Solution {
private:
vector<int> vec;
void traversal(TreeNode* root)
{
if(root == nullptr) { return; }
traversal(root->left);
vec.push_back(root->val);
traversal(root->right);
return;
}
public:
bool isValidBST(TreeNode* root) {
vec.clear();
traversal(root);
for(int i=1; i<vec.size(); ++i)
{
if(vec[i] <= vec[i-1]) { return false; }
}
return true;
}
};
530. 二叉搜索树的最小绝对差(√)
class Solution {
private:
vector<int> vec;
void traversal(TreeNode* root)
{
if(root == nullptr) { return; }
traversal(root->left);
vec.push_back(root->val);
traversal(root->right);
return;
}
public:
int getMinimumDifference(TreeNode* root) {
vec.clear();
int result;
traversal(root);
for(int i=1; i<vec.size(); ++i)
{
result = min(result, vec[i] - vec[i-1]);
}
return result;
}
};
自己写的。
class Solution {
private:
void inorder(TreeNode* root, vector<int>& vec)
{
if(root == nullptr) { return; }
if(root->left) { inorder(root->left, vec); }
vec.push_back(root->val);
if(root->right) { inorder(root->right, vec); }
}
public:
int getMinimumDifference(TreeNode* root) {
vector<int> result;
inorder(root, result);
int num = INT_MAX;
for(int i=1; i<result.size(); ++i)
{
num = num < (result[i]-result[i-1]) ? num : (result[i]-result[i-1]);
}
return num;
}
};
Carl:好好学习,掌握一下。
class Solution {
private:
int result = INT_MAX;
TreeNode* pre;
void inorder(TreeNode* root)
{
if(root == nullptr) { return; }
if(root->left) { inorder(root->left); }
if(pre != nullptr)
{
result = min(result, root->val - pre->val);
}
pre = root;
if(root->right) { inorder(root->right); }
}
public:
int getMinimumDifference(TreeNode* root) {
inorder(root);
return result;
}
};
501. 二叉搜索树中的众数(×)未学习。
235. 二叉搜索树的最近公共祖先(迭代 、 递归)
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
while(root != NULL)
{
if(root->val > p->val && root->val > q->val)
{
root = root->left;
}
else if(root->val < p->val && root->val < q->val)
{
root = root->right;
}
else
{
return root;
}
}
return NULL;
}
};
还不是完全理解。!!!
class Solution {
private:
TreeNode* travelsal(TreeNode* root, TreeNode* p, TreeNode* q)
{
if(root == NULL) { return NULL; }
if(root->val > p->val && root->val > q->val)
{
TreeNode* left = lowestCommonAncestor(root->left, p, q);
if(left != NULL) { return left; }
}
if(root->val < p->val && root->val < q->val)
{
TreeNode* right = lowestCommonAncestor(root->right, p, q);
if(right != NULL) { return right; }
}
return root;
}
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
return travelsal(root, p, q);
}
};
236. 二叉树的最近公共祖先
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root == NULL || root == p || root == q) { return root; }
TreeNode* left = lowestCommonAncestor(root->left, p, q);
TreeNode* right = lowestCommonAncestor(root->right, p, q);
if(left && right) { return root; }
if(left == NULL && right != NULL) { return right; }
else if(left != NULL && right == NULL) { return left; }
else { return NULL; }
}
};
701. 二叉搜索树中的插入操作
class Solution {
public:
TreeNode* insertIntoBST(TreeNode* root, int val) {
if(root == nullptr)
{
TreeNode* node = new TreeNode(val);
return node;
}
if(root->val < val) { root->right = insertIntoBST(root->right, val); }
if(root->val > val) { root->left = insertIntoBST(root->left, val); }
return root;
}
};
Carl(迭代版本)(×)
class Solution {
public:
TreeNode* insertIntoBST(TreeNode* root, int val) {
if(root == nullptr)
{
TreeNode* node = new TreeNode(val);
return node;
}
TreeNode* cur = root;
TreeNode* pre = root;
while(cur != nullptr)
{
pre = cur;
if(cur->val > val) { cur = cur->left; }
else { cur = cur->right; }
}
TreeNode* node = new TreeNode(val);
if(val < pre->val) { pre->left = node; }
else { pre->right = node; }
return root;
}
};
450.删除二叉搜索树中的节点
538. 把二叉搜索树转换为累加树
class Solution {
private:
int pre;
void traversal(TreeNode* cur)
{
if(cur == nullptr) { return; }
traversal(cur->right);
cur->val += pre;
pre = cur->val;
traversal(cur->left);
}
public:
TreeNode* convertBST(TreeNode* root) {
if(root == nullptr) { return nullptr; }
int pre = 0;
traversal(root);
return root;
}
};
重建二叉树(×)
105. 从前序与中序遍历序列构造二叉树
剑指 Offer 07. 重建二叉树
链接: 重建二叉树.
class Solution {
private:
unordered_map<int, int> index;
public:
TreeNode* BuildTreeHelper(vector<int>& preorder, vector<int>& inorder, int preorder_left, int preorder_right, int inorder_left, int inorder_right)
{
if(preorder_left > preorder_right) { return nullptr; }
// 前序遍历中的第一个节点就是根节点
int preorder_root = preorder_left;
// 在中序遍历中定位根节点
int inorder_root = index[preorder[preorder_root]];
// 先把根节点建立出来
TreeNode* root = new TreeNode(preorder[preorder_root]);
// 得到左子树中的节点数目
int size_left_subtree = inorder_root - inorder_left;
// 递归地构造左子树,并连接到根节点
// 先序遍历中「从 左边界+1 开始的 size_left_subtree」个元素就对应了
// 中序遍历中「从 左边界 开始到 根节点定位-1」的元素
root->left = BuildTreeHelper(preorder, inorder, preorder_left+1, preorder_left+size_left_subtree, inorder_left, inorder_root-1);
// 递归地构造右子树,并连接到根节点
// 先序遍历中「从 左边界+1+左子树节点数目 开始到 右边界」的元素就对应了
// 中序遍历中「从 根节点定位+1 到 右边界」的元素
root->right = BuildTreeHelper(preorder, inorder, preorder_left+size_left_subtree+1, preorder_right, inorder_root+1, inorder_right);
return root;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
int len = inorder.size();
// 构造哈希映射,帮助我们快速定位根节点
for(int i=0; i<len; ++i)
{
index[inorder[i]] = i;
}
return BuildTreeHelper(preorder, inorder, 0, len - 1, 0, len - 1);
}
};
106. 从中序与后序遍历序列构造二叉树
class Solution {
private:
TreeNode* traversal(vector<int>& inorder, vector<int>& postorder)
{
// 第一步
if(postorder.size() == 0) { return nullptr; }
// 第二步:后序遍历数组最后一个元素,就是当前的中间节点
int rootValue = postorder[postorder.size() - 1];
TreeNode* root = new TreeNode(rootValue);
// 叶子节点
if (postorder.size() == 1) return root;
// 第三步:找切割点
int delimiterIndex;
for(delimiterIndex=0; delimiterIndex<inorder.size(); ++delimiterIndex)
{
if(inorder[delimiterIndex] == rootValue) break;
}
// 第四步:切割中序数组,得到 中序左数组和中序右数组
// 左闭右开区间:[0, delimiterIndex)
vector<int> leftInorder(inorder.begin(), inorder.begin() + delimiterIndex);
// [delimiterIndex + 1, end)
vector<int> rightInorder(inorder.begin() + delimiterIndex + 1, inorder.end());
// postorder 舍弃末尾元素,因为这个元素就是中间节点,已经用过了
postorder.resize(postorder.size() - 1);
// 第五步:切割后序数组,得到 后序左数组和后序右数组
// 依然左闭右开,注意这里使用了左中序数组大小作为切割点
// [0, leftInorder.size)
vector<int> leftPostorder(postorder.begin(), postorder.begin() + leftInorder.size());
// [leftInorder.size(), end)
vector<int> rightPostorder(postorder.begin() + leftInorder.size(), postorder.end());
// 第六步
root->left = traversal(leftInorder, leftPostorder);
root->right = traversal(rightInorder, rightPostorder);
return root;
}
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
if(inorder.size() == 0 || postorder.size() == 0) { return nullptr; }
return traversal(inorder, postorder);
}
};
654. 最大二叉树
class Solution {
public:
TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
TreeNode* node = new TreeNode(0);
if(nums.size() == 1) { node->val = nums[0]; return node; }
// 找到数组中最大的值和对应的下标
int maxValue = 0;
int maxValueIndex = 0;
for(int i=0; i<nums.size(); ++i)
{
if(nums[i] > maxValue)
{
maxValue = nums[i];
maxValueIndex = i;
}
}
node->val = maxValue;
// 最大值所在的下表左区间 构造左子树
if(maxValueIndex > 0)
{
vector<int> newVec(nums.begin(), nums.begin() + maxValueIndex);
node->left = constructMaximumBinaryTree(newVec);
}
// 最大值所在的下表右区间 构造右子树
if(maxValueIndex < nums.size() - 1)
{
vector<int> newVec(nums.begin() + maxValueIndex + 1, nums.end());
node->right = constructMaximumBinaryTree(newVec);
}
return node;
}
};
617. 合并二叉树
class Solution {
public:
TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
if(root1 == nullptr) { return root2; }
if(root2 == nullptr) { return root1; }
// 修改了root1的数值和结构
root1->val += root2->val; // 中
root1->left = mergeTrees(root1->left, root2->left); // 左
root1->right = mergeTrees(root1->right, root2->right); // 右
return root1;
}
};
700. 二叉搜索树中的搜索
class Solution {
public:
TreeNode* searchBST(TreeNode* root, int val) {
if(root == nullptr || root->val == val) { return root; }
if(root->val > val) return searchBST(root->left, val);
if(root->val < val) return searchBST(root->right, val);
return nullptr;
}
};
Binary Tree Level Order Traversal
two Queues
one Queue + Dummy Node
one Queue (best)
103. 二叉树的锯齿形层序遍历
链接: 103. 二叉树的锯齿形层序遍历.
Print Range in a Binary Search Tree
Given two values k1 and k2 (where k1 < k2) and a root pointer to a
Binary Search Tree. Print all the keys of tree in range k1 to k2. i.e. print all x such that k1<=x<=k2 and x is a key of given BST. Print all the keys in increasing order.
For example, if k1 = 10 and k2 = 22, then your function should print 12, 20 and 22.
Trie Tree
字典树(trie or prefix tree)是⼀个26叉树,⽤于在⼀个集合中检索⼀个字符串,或者字符串前缀。字典树的每个节点有⼀个指针数组代表其所有⼦树,其本质上是⼀个hash table,因为⼦树所在的位置(index)本⾝,就代表了节点对应的字母。
Symmetric Tree/对称二叉树
101. 对称二叉树
Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center).
class Solution {
public:
bool compare(TreeNode* left, TreeNode* right)
{
// 首先排除空节点的情况
if((left == nullptr) && (right != nullptr)) { return false; }
else if(left != nullptr && right == nullptr) { return false; }
else if(left == nullptr && right == nullptr) { return true; }
// 排除了空节点,再排除数值不相同的情况
else if(left->val != right->val) { return false; }
// 此时就是:左右节点都不为空,且数值相同的情况
// 此时才做递归,做下一层的判断
bool outside = compare(left->left, right->right);
bool inside = compare(left->right, right->left);
bool isSame = outside && inside;
return isSame;
}
bool isSymmetric(TreeNode* root) {
if(root == nullptr) { return true; }
return compare(root->left, root->right);
}
};
类似题目:
100. 相同的树
class Solution {
public:
bool compare(TreeNode* p, TreeNode* q)
{
if(p == nullptr && q != nullptr) { return false; }
else if(p != nullptr && q == nullptr) { return false; }
else if(p == nullptr && q == nullptr) { return true; }
else if (p->val != q->val) { return false; }
bool left = compare(p->left, q->left);
bool right = compare(p->right, q->right);
bool isSame = left && right;
return isSame;
}
bool isSameTree(TreeNode* p, TreeNode* q) {
if(p == nullptr && q == nullptr) { return true; }
return compare(p, q);
}
};
572. 另一棵树的子树
class Solution {
public:
bool isSubtree(TreeNode* root, TreeNode* subRoot) {
if(root == nullptr) { return false; }
if(subRoot == nullptr) { return true; }
if(root->val == subRoot->val)
{
if(matchTree(root, subRoot)) { return true; }
}
return isSubtree(root->left, subRoot) || isSubtree(root->right, subRoot);
}
bool matchTree(TreeNode* root, TreeNode* subRoot)
{
if(root == nullptr && subRoot == nullptr) { return true; }
if(root == nullptr || subRoot == nullptr) { return false; }
if(root->val != subRoot->val) { return false;}
return matchTree(root->left, subRoot->left) &&
matchTree(root->right, subRoot->right);
}
};
Binary Search Tree Iterator
Design an iterator over a binary search tree with the following rules:
- Elements are visited in ascending order (i.e. an in-order traversal)
- next() and hasNext() queries run in O(1) time in average.
Sorted List to BST
Given a singly linked list where elements are sorted in ascending order, convert it to a height balanced BST.