面试题 04.01. 节点间通路
class Solution {
public:
bool findWhetherExistsPath(int n, vector<vector<int>>& graph, int start, int target) {
vector<vector<int>> vec(n);
vector<bool> visit(n,false);
for(int i=0; i<graph.size(); ++i){
vec[graph[i][0]].push_back(graph[i][1]);
}
// return dfs(vec, visit, start, target);
return bfs(vec, visit, start, target);
}
bool dfs(vector<vector<int>>& vec, vector<bool>& visit, int start, int target){
if(start == target){
return true;
}
visit[start] == true;
for(auto it : vec[start]){
if(dfs(vec, visit, it, target)){
return true;
}
}
visit[start] == false;
return false;
}
bool bfs(vector<vector<int>>& vec, vector<bool>& visit, int start, int target){
queue<int> q;
q.push(start); // 把起始点加入队列
while(!q.empty()){
int now = q.front();
if(now == target){
return true;
}
visit[now] = true;
for(auto it : vec[now]){
if(visit[it] == false){
q.push(it);
}
}
q.pop();
}
return false;
}
};
面试题 04.02. 最小高度树
跑出来和测试用例结果不同,其实没有错误,点提交可以AC,因为结果并不唯一。
/**
* 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* sortedArrayToBST(vector<int>& nums) {
return dfs(nums, 0, nums.size()-1);
}
TreeNode* dfs(vector<int>& nums, int left, int right){
if(left > right){
return NULL;
}
int mid = (left + right) >> 1;
TreeNode* ptr = new TreeNode(nums[mid]);
ptr->left = dfs(nums, left, mid-1);
ptr->right = dfs(nums, mid+1, right);
return ptr;
}
};
面试题 04.03. 特定深度节点链表
参考模板:https://www.cnblogs.com/cell-coder/p/12344619.html
模板描述:
void 按层数层序遍历(根节点){
初始化队列,临时变量;
将根节点放入队列中;
while(队列不为空){
获取队列长度size;
while(size不为0){
取出队首结点;
if(队首结点的左孩子不为NULL) 将队首结点的左孩子放进队列;
if(队首结点的右孩子不为NULL) 将队首结点的右孩子放进队列;
弹出队首结点;
完成一个结点的遍历,size--;
}
}
}
模板代码:
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
void BFS(TreeNode* root){
int size=0;
TreeNode *temp;
queue<TreeNode*> que;
que.push(root);
while(!que.empty()){
size=que.size();
while(size--){
temp=que.front();
que.pop();
if(temp->left!=NULL) que.push(temp->left);
if(temp->right!=NULL) que.push(temp->right);
}
}
}
解题参考:https://www.cnblogs.com/cell-coder/p/12344685.html
双100%
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
vector<ListNode*> listOfDepth(TreeNode* tree) {
int size = 0;
TreeNode * temp;
queue<TreeNode*> q;
q.push(tree);
vector<ListNode*> res;
while(!q.empty()){
size = q.size();
ListNode* head = new ListNode(-1); // 值不重要,重要的是个伪头节点
ListNode* p = head;
while(size--){
temp = q.front();
if(temp->left){q.push(temp->left);}
if(temp->right){q.push(temp->right);}
q.pop();
p->next = new ListNode(temp->val);
p = p->next;
}
res.push_back(head->next);
}
return res;
}
};
面试题 04.04. 检查平衡性
方法1:定义getHeight函数,只是为了获得一个节点的最大深度
/**
* 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 isBalanced(TreeNode* root) {
if(root == NULL){
return true;
}
if(abs(getHeight(root->left) - getHeight(root->right)) > 1){
return false;
}
return isBalanced(root->left) && isBalanced(root->right);
}
int getHeight(TreeNode* root){
if(root == NULL){
return 0;
}
return max(getHeight(root->left),getHeight(root->right))+1;
}
};
方法二:定义一个dfs函数,同时完成深度计算和合法性检查
/**
* 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 isBalanced(TreeNode* root) {
return dfs(root) != -1;
}
int dfs(TreeNode* root) {
if (root == NULL) return 0;
int left = dfs(root->left);
if (left == -1) return -1;
int right = dfs(root->right);
if (right == -1 || abs(left - right) > 1) return -1;
return max(left, right) + 1;
}
};
面试题 04.05. 合法二叉搜索树
/**
* 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 isValidBST(TreeNode* root) {
if(root == NULL){
return true;
}
vector<int> ans;
dfs(ans, root);
for(int i=1; i<ans.size(); ++i){
if(ans[i-1] >= ans[i]){// 因为输入[1,1],应输出false,所以这里得加=
return false;
}
}
return true;
}
void dfs(vector<int>& ans, TreeNode* root){
if(root == NULL){
return;
}
dfs(ans, root->left);
visit(ans, root);
dfs(ans,root->right);
}
void visit(vector<int>& ans, TreeNode* root){
ans.push_back(root->val);
}
};
注意:
for(int i=1; i<ans.size(); ++i){
if(ans[i-1] >= ans[i]){// 因为输入[1,1],应输出false,所以这里得加=
return false;
}
}
与下列写法相同,注意边界条件:
for(int i=0; i<ans.size()-1; ++i){
if(ans[i+1] <= ans[i]){// 因为输入[1,1],应输出false,所以这里得加=
return false;
}
}
面试题 04.06. 后继者
方法1:BST + 递归 (BST是二叉搜索树)
20% 100%
如果结点 p 的值大于等于 root 的值,说明 p 的后继结点在 root 右子树中,那么就递归到右子树中查找。
如果结点 p 的值小于 root 的值,说明 p 在 root 左子树中,而它的后继结点有两种可能,要么也在左子树中,要么就是 root:
如果左子树中找到了后继结点,那就直接返回答案。
如果左子树中没有找到后继结点,那就说明 p 的右儿子为空,那么 root 就是它的后继结点。
/**
* 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* inorderSuccessor(TreeNode* root, TreeNode* p) {
if(root == NULL || p == NULL){
return NULL;
}
if(p->val >= root->val){
return inorderSuccessor(root->right, p);
}
TreeNode* left = inorderSuccessor(root->left, p);
return ((left == NULL)? root : left);
}
};
方法2:BST+非递归
如果 p 有右儿子,那么它的后继结点就是右子树的最左边的儿子。
如果 p 没有右儿子,那么它的后继结点就是,沿着 p 往上到 root 的路径中,第一个左儿子在路径上的结点。因为这个结点的左子树中 p 是最右边的结点,是最大的,所以它就是 p 的后继结点。因为是二叉搜索树,我们就可以从根结点开始往 p 走,根据结点值的大小决定走的方向。
/**
* 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* inorderSuccessor(TreeNode* root, TreeNode* p) {
if(root == NULL || p == NULL){
return NULL;
}
if(p->right){
p = p->right; // 右子树
while(p->left){ // 找到右子树的最左节点
p = p->left;
}
return p;
}
TreeNode* res = NULL;
while(root != p){
if(root->val < p->val){
root = root->right;
}else{
res = root;
root = root->left;
}
}
return res;
}
};
拓展:
一般树+递归
那如果是一般的二叉树,中序遍历就不满足单调递增了,这时候我们就只能找出中序遍历的结点顺序,然后才能得到 p 的后继结点。
所以我们直接采用递归来做中序遍历就行了,中序遍历结果保存下来,最后取 p 的下一个结点。
/**
* 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* inorderSuccessor(TreeNode* root, TreeNode* p) {
vector<TreeNode*> res;
inorder(root, res);
res.push_back(NULL);
for(int i=0; i<res.size()-1;++i){
if(res[i] == p){
return res[i+1];
}
}
return NULL;
}
void inorder(TreeNode* root, vector<TreeNode*>& res){
if(root->left){
inorder(root->left,res);
}
res.push_back(root);
if(root->right){
inorder(root->right, res);
}
}
};
一般树+非递归
当然还可以采用栈来做中序遍历,这样就是非递归了。同样结果保存下来,最后取 p 的下一个结点。
/**
* 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* inorderSuccessor(TreeNode* root, TreeNode* p) {
vector<TreeNode*> res;
stack<TreeNode*> st;
while(!st.empty() || root){
while(root){
st.push(root);
root = root->left;
}
root = st.top();
st.pop();
res.push_back(root);
root = root->right;
}
res.push_back(NULL);
for(int i=0; i<res.size()-1; ++i){
if(res[i] == p){
return res[i+1];
}
}
return NULL;
}
};
LeetCode上没有4.07
面试题 04.08. 首个共同祖先
递归代码的执行过程,有空的时候看:https://leetcode-cn.com/problems/diameter-of-binary-tree/solution/shi-pin-jie-shi-di-gui-dai-ma-de-yun-xing-guo-chen/
/**
* 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* 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;
}
return left ? left : right;
}
};
面试题 04.09. 二叉搜索树序列
题目等级:困难
很牛的一个解法:https://blog.csdn.net/zjulyx1993/article/details/106127257
原版:
/**
* 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:
vector<vector<int>> BSTSequences(TreeNode *root) {
vector<vector<int>> res;
if (!root) {
res.push_back({});
return res;
}
function<void(TreeNode *, vector<TreeNode *>, vector<int>)> findPath =
[&](TreeNode *curNode, vector<TreeNode *> nextValidNodes, vector<int> path) {
if (curNode->left) {
nextValidNodes.push_back(curNode->left);
}
if (curNode->right) {
nextValidNodes.push_back(curNode->right);
}
if (nextValidNodes.empty()) {
res.push_back(path);
return;
}
int size = nextValidNodes.size();
for (int i = 0; i < size; ++i) {
swap(nextValidNodes[i], nextValidNodes[size - 1]);
vector<TreeNode *> newq(&nextValidNodes[0], &nextValidNodes[size - 1]);
swap(nextValidNodes[i], nextValidNodes[size - 1]);
path.push_back(nextValidNodes[i]->val);
findPath(nextValidNodes[i], newq, path);
path.pop_back();
}
};
findPath(root, {}, {root->val});
return res;
}
};
热心网友翻版:
/**
* 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:
vector<vector<int>> ans;
vector<vector<int>> BSTSequences(TreeNode* root) {
if(root == NULL) return {{}};
queue<TreeNode*> que;
vector<int> path;
path.push_back(root->val);
core(root,que,path);
return ans;
}
void core(TreeNode* root,queue<TreeNode*> que,vector<int> &path){
if(!root) return;
if(root->left) que.push(root->left);
if(root->right) que.push(root->right);
if(que.empty()){
ans.push_back(path);
return;
}
int n=que.size();
while(n--){
TreeNode* cur=que.front();que.pop();
path.push_back(cur->val);
core(cur,que,path);
que.push(cur);
path.pop_back();
}
}
};
普通解法:https://blog.csdn.net/qq_21201267/article/details/105422633
/**
* 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 {
vector<vector<int>> ans;
vector<int> temp;
deque<TreeNode*> q;
public:
vector<vector<int>> BSTSequences(TreeNode* root) {
if(!root)
return {{}};
q.push_back(root);
dfs();
return ans;
}
void dfs()
{
if(q.empty())
{
ans.push_back(temp);
return;
}
int size = q.size();
while(size--)//这层有几个人
{
TreeNode *tp = q.front();
q.pop_front(); //队列,第一个人出队
temp.push_back(tp->val);
int children = 0;
if(tp->left)//把下层加入队列
{
q.push_back(tp->left);
children++;
}
if(tp->right)
{
q.push_back(tp->right);
children++;
}
dfs();
while(children--)
q.pop_back();//把下层的删除
q.push_back(tp);//第一个人去队尾
temp.pop_back();
}
}
};
面试题 04.10. 检查子树
/**
* 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 checkSubTree(TreeNode* t1, TreeNode* t2) {
if(t2 == NULL){
return true;
}
if(t1 == NULL){
return false;
}
if(t1->val != t2->val){
return checkSubTree(t1->left, t2)|| checkSubTree(t1->right, t2);
}
return checkSubTree(t1->left, t2->left) && checkSubTree(t1->right, t2->right);
}
};
面试题 04.11. 随机节点
这题LeetCode上没有
面试题 04.12. 求和路径
方法一:暴力递归:DFS递归
/**
* 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:
int res = 0;
int pathSum(TreeNode* root, int sum) {
if(root == NULL){
return 0;
}
dfs(root, sum);
pathSum(root->left, sum);
pathSum(root->right, sum);
return res;
}
void dfs(TreeNode* root, int sum){
if(root == NULL){
return;
}
int cursum = 0 ;
cursum += root->val;
if(cursum == sum){
res++;
}
dfs(root->left, sum-cursum);
dfs(root->right,sum-cursum);
}
};
方法二:前缀和。就是到达当前元素的路径上,之前所有元素的和。
参考1:https://www.cnblogs.com/yonezu/p/13324770.html
参考2:https://leetcode-cn.com/problems/paths-with-sum-lcci/solution/qian-zhui-he-de-ying-yong-di-gui-hui-su-by-shi-huo/