方法论:
- 看题五分钟,不会做,看解析;
- 先看中文站,再看国际站;
- 选择最优解析;
- 回头再来写
面试四步走:
- 和面试官,探讨题目限制条件;
- 说说可能解,选择最优解;
- 码字;
- 跑测试用例
背景
思维要点:
- 不要人肉进行递归
- 找到最近最简方法,将其拆解成可重复解决的问题(重复子问题)
- 数学归纳法思维
找到一种写代码的感觉!!!
void recur(int level, int param) {
// terminator
if (level > MAX_LEVEL) {
// process result
return;
}
// process current logic
process(level, param);
// drill down
recur(level: level + 1, newParam);
// restore current status
}
C++种stringstream介绍,这里需要注意getline
的用法;
// extract to string
#include <iostream>
#include <sstream>
#include <string>
int main ()
{
std::string name;
std::string name1;
std::stringstream str("fan#zhi#hao#");
std::getline (str, name, '#');
std::cout << "Hello, " << name << "!\n";
std::getline (str, name1, '#');
std::cout << "Hello, " << name1 << "!\n";
return 0;
}
104.二叉树的最大深度
可能解:
- 递归求解
- 迭代求解
# 1. 递归求解
class Solution {
public:
int maxDepth(TreeNode* root) {
// terminator
if (root == nullptr) return 0;
//drill down
return max(maxDepth(root->left), maxDepth(root->right)) + 1;
}
};
# 2. 迭代求解
class Solution {
public:
int maxDepth(TreeNode* root) {
if (root == nullptr) return 0;
int res = 0;
queue<TreeNode*> pq;
pq.push(root);
while (!pq.empty()) {
int size = pq.size();
for (int i = 0; i < size; i++) {
TreeNode* tmp = pq.front();
pq.pop();
if (tmp->left) pq.push(tmp->left);
if (tmp->right) pq.push(tmp->right);
}
res++;
}
return res;
}
};
111.二叉树的最小深度
可能解:
- 递归求解
# 1. 递归求解
class Solution {
public:
int minDepth(TreeNode* root) {
// terminator
if (root ==nullptr) return 0;
// dirll down
int left = minDepth(root->left);
int right = minDepth(root->right);
// restore current status
if (left == 0 || right == 0) return left+ right +1;
return min(left, right) + 1;
}
};
98.验证二叉搜索树
可能解:
-
定义函数
help(bottom. root. upper)
-
利用二叉搜索树中序遍历有序性,验证二叉搜索树;
# 1T
class Solution {
public:
bool isValidBST(TreeNode* root) {
return helper(LONG_MIN, root, LONG_MAX);
}
private:
bool helper(long long bottom, TreeNode* root, long long upper) {
if (root == nullptr) return true;
if (root->val <= bottom || root->val >= upper) return false;
return helper(root->val, root->right, upper) && helper(bottom, root->left, root->val);
}
};
isValidBST(root)
的定义为:如果以root为根的树为 BST, 那么改函数返回ture
,否则返回false
;以下为中序递归的模板!!!
# 2T
class Solution {
public:
TreeNode* pre;
bool isValidBST(TreeNode* root) {
// terminator
if (root == nullptr) return true;
// process current Logic
// drill down
if (!isValidBST(root->left)) {
return false;
}
if (pre != nullptr && pre->val >= root->val){
return false;
}
pre = root;
if (!isValidBST(root->right)){
return false;
}
// restore current status
return true;
}
};
226.翻转二叉树
以下会写三种方法,其中第一种、第二种类似(同为递归),第三种为迭代方法;迭代方法仍旧是利用stack
模拟递归;
# 1.递归方法1
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
if (root == nullptr) return nullptr;
//if (root->right == nullptr && root->left == nullptr) return root;
invertTree(root->left);
invertTree(root->right);
swap(root->left, root->right);
return root;
}
};
# 2.递归方法2
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
// terminator
if (root == nullptr) return nullptr;
// process current logic
TreeNode* tmp = root->left;
root->left = invertTree(root->right);
root->right = invertTree(tmp);
// restore current status
return root;
}
};
# 3. 迭代方法
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
stack<TreeNode*> sk;
sk.push(root);
while (!sk.empty()) {
TreeNode* tmp = sk.top();
sk.pop();
if (tmp == nullptr) continue;
sk.push(tmp->right);
sk.push(tmp->left);
swap(tmp->right, tmp->left);
}
return root;
}
};
105.从前序与中序遍历序列构造二叉树
思路:利用前序遍历为:[preroot, tree(preroot->left), tree(preroot->left)],中序遍历为:[tree(inroot->left), inroot, tree(inroot->right)]的特性,设计递归函数mybuildtree(preorder, pre, end, iL)
,其中iL也就是中序遍历中root的下标。其中不同方法:主要体现在根据根据preroot->val
找其在中序遍历的坐标不同上,以下代码是 利用map来记录坐标的不同 看代码:
class Solution {
public:
unordered_map<int, int> umap;
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
for (int i = 0; i < inorder.size(); i++) {
umap[inorder[i]] = i;
}
return myBuildTree(preorder, 0, preorder.size() - 1, 0);
}
private:
TreeNode* myBuildTree(vector<int>& preorder, int pre, int end, int inL){
if (pre > end) return nullptr;
int index = umap[preorder[pre]];
int leftNum = index - inL;
TreeNode* root = new TreeNode(preorder[pre]);
root->left = myBuildTree(preorder, pre + 1, pre + leftNum, inL);
root->right = myBuildTree(preorder, pre + leftNum + 1, end, index + 1);
return root;
}
};
236.二叉树的最近公共祖先
可能解:
- 递归求解的基本路子;
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
// terminator
if (root == nullptr) return nullptr; // 断臂操作
if (root == p || root == q) return root;
// process current logic
// drill down
TreeNode* left = lowestCommonAncestor(root->left, p, q);
TreeNode* right = lowestCommonAncestor(root->right, p, q);
// restore current status
if (left == nullptr && right == nullptr) return nullptr;
if (left ==nullptr) return right;
if (right == nullptr) return left;
return root;
}
};
22.括号生成
思路:由于这类题有无限解,一定是递归回溯方法。设计函数_generate(int left, int right, int n, string str)
,因此需要考虑以下几点:
- 终止条件terminator是:括号数量,
left == right
,则为符合条件的一个; - 递归条件:left < n, drill down,
_generate(left + 1, right, n, str + '(')
- 递归条件:left > right, drill down,
_generate(left, right+1, n, str + ')')
class Solution {
public:
vector<string> res;
vector<string> generateParenthesis(int n) {
_generate(0, 0, n, "");
return res;
}
private:
void _generate(int left, int right, int n, string str) {
if (left == n && right == n) {
res.push_back(str);
}
if (left < n) _generate(left + 1, right, n, str + '(');
if (left > right) _generate(left, right + 1, n, str + ')');
}
};
参考
- 这个链接是关于stack和queue相关题目的集合——Basic C++ iterative solution with detailed explanations. Super easy for beginners.
- 极客时间-算法训练营-覃超
- leetcode中文站
- leetcode国际站 (将力扣中文链接,后面的-cn去掉,就是该题的国际站)