程序员面试金典 04刷题回忆录
给定有向图,设计一个算法,找出两个节点之间是否存在一条路径。
04.01
class Solution {
public:
bool findWhetherExistsPath(int n, vector<vector<int>>& graph, int start, int target) {
if(start == target) return true;
for(auto& e : graph)
if(e[1] == target)
return findWhetherExistsPath(n,graph,start,e[0]);
return false;
}
};
dfs递归,相当于从终点往前走了。
给定一个有序整数数组,元素各不相同且按升序排列,编写一个算法,创建一棵高度最小的二叉搜索树。
04.02
class Solution {
public:
TreeNode* sortedArrayToBST(vector<int>& nums) {
int len=nums.size();
return dfs(nums,0,len);
}
TreeNode *dfs(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=dfs(nums,left,mid);
root->right=dfs(nums,mid+1,right);
return root;
}
};
有序必二分,找中点来建树,可以让高度最小。
其实就是BFS,没啥好说的。
只不过返回的是vector
04.03
class Solution {
public:
vector<ListNode*> listOfDepth(TreeNode* tree) {
if(!tree) return{};
vector<ListNode*>res;
queue<TreeNode*>Q;
Q.push(tree);
while(!Q.empty())
{
int size1=Q.size();
ListNode*p=new ListNode(0);
ListNode*q=p;
for(int i=0;i<size1;i++)
{
TreeNode* temp=Q.front();
Q.pop();
if(temp->left)
{
Q.push(temp->left);
}
if(temp->right)
{
Q.push(temp->right);
}
q->next=new ListNode(temp->val);
q=q->next;
}
res.push_back(p->next);
}
return res;
}
};
04.04
肯定是自下往上查平衡。定义一个res,一旦不平衡置0
class Solution {
public:
bool isBalanced(TreeNode* root) {
bool res = true;
depth(root, res);
return res;
}
private:
int depth(TreeNode* root, bool& res){
if(root == NULL) return 0;
int left = depth(root->left, res) + 1;
int right = depth(root->right, res) + 1;
if(abs(left-right) > 1) res = false;
return max(left,right);
}
};
判断一棵树是不是BST,即进行中序遍历,看满不满足升序。
递归:
class Solution {
public:
TreeNode* pre=nullptr;
bool isValidBST(TreeNode* root) {
if(root==nullptr) return 1;
if(!isValidBST(root->left)) return 0;
if(pre && pre->val>= root->val)return 0;
pre=root;
if(!isValidBST(root->right))return 0;
return 1;
}
};
迭代:
class Solution {
public:
bool isValidBST(TreeNode* root) {
if(root==nullptr) return 1;
TreeNode* pre=nullptr;
stack<TreeNode*> stk;
while(root!=nullptr || !stk.empty())
{
if(root!=nullptr)
{
stk.push(root);
root=root->left;
}
else
{
root=stk.top();
stk.pop();
if(pre!=nullptr && root->val<= pre->val) return 0;
pre=root;
root=root->right;
}
}
return 1;
}
};
给定节点p,找到其中序遍历的后一个元素。
如果是BST,则简化如下:
class Solution {
public:
TreeNode* inorderSuccessor(TreeNode* root, TreeNode* p) {
if(root==nullptr || p==nullptr) return nullptr;
if(root->val <= p->val) return inorderSuccessor(root->right,p);
else
{
TreeNode* left=inorderSuccessor(root->left,p);
return left? left:root;
}
}
};
更多递归非递归;BST或者是普通树;以及一般树的Morris遍历。
这样进行Morris遍历,得到的res里面确实没有重复的。用O(N)的时间复杂度和O(1)的空间复杂度。确实顶。
解答
找出二叉树中某两个节点的第一个共同祖先。
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(!root || 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 && !right) return left;
return right;
}
};
这个我好像没有看懂,打个星。
/**
* 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<int> path;
vector<vector<int>> res;
vector<vector<int>> BSTSequences(TreeNode* root) {
if (!root) return {{}};
deque<TreeNode*> dq;
dq.push_back(root);
dfs(dq);
return res;
}
void dfs(deque<TreeNode*>& dq) {
// base case
if (dq.empty()) {
res.push_back(path);
return;
}
int size = dq.size();
for (int i = 0; i < size; i++) {
TreeNode* node = dq.front();
dq.pop_front();
// 将当前值加入path
path.push_back(node -> val);
// 将当前节点的子节点加入选择节点
if (node -> left) dq.push_back(node -> left);
if (node -> right) dq.push_back(node -> right);
// 下一轮递归
dfs(dq);
// 回溯选择列表
if (node -> left) dq.pop_back();
if (node -> right) dq.pop_back();
// 把加入的子节点pop出后,还要将当前节点重新加入选择列表
dq.push_back(node);
// 回溯path
path.pop_back();
}
}
};
解法来源
很简单的递归,注意nullptr即可。略
/**
* 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 pathSum(TreeNode* root, int sum) {
++prefixSum[0];
dfs(root,sum,0);
return ans;
}
void dfs(TreeNode* root, int sum, int curSum) {
if (!root) return;
curSum += root -> val;
if (prefixSum.find(curSum - sum) != prefixSum.end()) ans += prefixSum[curSum - sum]; // 可能存在多条路径有相同的前缀和
++prefixSum[curSum];
if (root -> left) dfs(root -> left,sum,curSum);
if (root -> right) dfs(root -> right,sum,curSum);
--prefixSum[curSum]; // 回溯时消去当前节点产生的前缀和
return;
}
private:
unordered_map<int,int> prefixSum;
int ans = 0;
};
前缀和,比如一个链表5,4,11,7
他的前缀和为5,9,20,27
然后sum=22.cursum=27,27-22=9,就把9的哈希值(有几个前缀和为9)加上。
回溯要记得,相当于。对左子树处理的数据,哈希值,不能给右子树用。
总体而言,遇到回溯的,还是感觉比较难。
现在连回溯都看不懂了,变菜了,寄了。
今天看了100页的机器学习,感觉还是有大佬带,比较舒服。
赶紧学,赶紧赚钱,然后抱着心爱的女孩子,天天给你烤蛋挞。