[LEECODE]算法进阶自练习5-6 递归&哈希表
5.递归
简单
- 二叉树的最大深度 leetcode 104 递归解法(简单易理解):
int maxDepth(TreeNode* root) {
if(root == nullptr) return 0;
int leftDepth = maxDepth(root->left);
int rightDepth = maxDepth(root->right);
return max(leftDepth, rightDepth) + 1;
}
广度优先搜索(层序遍历):
int maxDepth(TreeNode* root) {
int ans = 0;
if(!root) return ans;
queue<TreeNode*> queue;
queue.push(root);
while(!queue.empty()){
int size = queue.size();
while(size > 0){
TreeNode* node = queue.front(); queue.pop();
if(node->left) queue.push(node->left);
if(node->right) queue.push(node->right);
size--;
}
ans++;
}
return ans;
}
- 对称二叉树 leetcode 101 递归解法:
bool check(TreeNode* l, TreeNode* r){
if(!l && !r) return true; // 左右节点都为空了
if(!l || !r) return false; // 有一个节点不为空
return l->val == r->val && check(l->left,r->right) && check(l->right,r->left);
}
bool isSymmetric(TreeNode* root) {
if(!root) return true;
return check(root->left, root->right);
}
层序遍历解法:
bool check(TreeNode* l, TreeNode* r){
queue<TreeNode*> queue;
queue.push(l);queue.push(r);
while(!queue.empty()){
TreeNode* tl = queue.front(); queue.pop();
TreeNode* tr = queue.front(); queue.pop();
if(!tl && !tr) continue;
if((!tl || !tr) || tl->val != tr->val) return false;
queue.push(tl->left);
queue.push(tr->right);
queue.push(tl->right);
queue.push(tr->left);
}
return true;
}
bool isSymmetric(TreeNode* root) {
if(!root) return true;
return check(root->left, root->right);
}
- 二叉树的最小深度 leetcode 111 递归解法:
int minDepth(TreeNode* root) {
if(!root) return 0;
if(root->left == nullptr && root->right == nullptr) return 1;
int minDep = INT_MAX;
if(root->left){
minDep = min(minDep,minDepth(root->left));
}
if(root->right){
minDep = min(minDep,minDepth(root->right));
}
return minDep + 1; // +1是加上当前节点
}
广度优先解法:
int minDepth(TreeNode* root) {
if(!root) return 0;
int ret = 0;
queue<pair<TreeNode*, int>> queue;
queue.emplace(root,1);
while (!queue.empty()) {
TreeNode *node = queue.front().first;
int depth = queue.front().second;
queue.pop();
if (node->left == nullptr && node->right == nullptr) {
return depth;
}
if (node->left != nullptr) {
queue.emplace(node->left, depth + 1);
}
if (node->right != nullptr) {
queue.emplace(node->right, depth + 1);
}
}
return 0;
}
- 二叉搜索树节点最小距离 leetcode 783
注意此题是求
任意两个节点的差值递归解法:
class Solution {
public:
vector<int> nums;
void collection(TreeNode* root){
if(!root) return;
if(root->left) collection(root->left);
nums.push_back(root->val);
if(root->right) collection(root->right);
}
int minDiffInBST(TreeNode* root) {
int min = INT_MAX;
collection(root);
for(int i = 1; i< nums.size(); i++){
min = min > abs(nums[i] - nums[i-1]) ? abs(nums[i] - nums[i-1]) : min;
}
return min;
}
};
深度优先遍历解法:
class Solution {
public:
vector<int> nums;
void collection(TreeNode* root){
if(!root) return;
stack<TreeNode*> st;
while(root || !st.empty()){
while(root){
st.push(root);
root = root->left;
}
if(!st.empty()){
root = st.top();
st.pop();
nums.push_back(root->val);
root = root->right;
}
}
}
int minDiffInBST(TreeNode* root) {
int min = INT_MAX;
collection(root);
for(int i = 1; i< nums.size(); i++){
min = min > abs(nums[i] - nums[i-1]) ? abs(nums[i] - nums[i-1]) : min;
}
return min;
}
};
- 二叉搜索树的范围和 leetcode 938 这个题目很简单,但是题目没有说明白,乍一看很懵,看了题解才知道这样啊。如果根节点值>=L&& <=R 计算左右子树和,如果根节点值<L计算右子树,如果根节点值>R计算左子树即可,这样递归就很简单了。
class Solution {
public:
int num = 0;
void rangeSum(TreeNode* root, int L, int R){
if(!root) return;
if(root->val >= L && root->val <= R){
num += root->val;
rangeSum(root->right,L,R);
rangeSum(root->left,L,R);
}
if(root->val > R){
rangeSum(root->left,L,R);
}
if(root->val < L){
rangeSum(root->right,L,R);
}
}
int rangeSumBST(TreeNode* root, int L, int R) {
rangeSum(root, L, R);
return num;
}
};
非递归版本就更容易了,直接全部遍历然后计算和就行了,这里其实应该可以优化如果在L和R之间的去遍历就可以了,其他的就没必要处理了。
class Solution {
public:
int num = 0;
void rangeSum(TreeNode* root, int L, int R){
if(!root) return;
stack<TreeNode*> st;
while(!st.empty() || root){
while(root){
st.push(root);
root = root->left;
}
if(!st.empty()){
root = st.top();
st.pop();
if(root->val >= L && root->val <= R){
num += root->val;
}
root = root->right;
}
}
}
int rangeSumBST(TreeNode* root, int L, int R) {
rangeSum(root, L, R);
return num;
}
};
中等
- 二叉树的最近公共祖先 leetcode 236 递归解法,理解思路可以参考这里(leetcode-cn.com/problems/lo…
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
/*
1.如果 p 和 q 都存在,则返回它们的公共祖先;
2.如果只存在一个,则返回存在的一个;
3. 如果 p 和 q 都不存在,则返回NULL
*/
if(!root) return nullptr;
if(root == p || root == q) return root;
TreeNode* l = lowestCommonAncestor(root->left,p,q);
TreeNode* r = lowestCommonAncestor(root->right,p,q);
if(!l) return r; // p q在右子树 注意这里判断条件是先判断为空的, 不然走不到 l&&r
if(!r) return l; // p q在左子树 注意这里判断条件是先判断为空的, 不然走不到 l&&r
if(l && r) return root; // p q在左右两个子树
return nullptr;
}
记录父节点,然后遍历查找最后的一个共同的父节点。
class Solution {
public:
unordered_map<int, TreeNode*> fa;
unordered_map<int, bool> vi;
void dfs(TreeNode* root){
if(root->left){
fa[root->left->val] = root;
dfs(root->left);
}
if(root->right){
fa[root->right->val] = root;
dfs(root->right);
}
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
fa[root->val] = nullptr;
dfs(root);
while(p != nullptr){
vi[p->val] = true;
p = fa[p->val];
}
while(q != nullptr){
if(vi[q->val]) return q;
q = fa[q->val];
}
return nullptr;
}
};
6.哈希表
简单
- 两数之和 leetcode 1 这里就用哈希表来解决就行了,还有几个解法,我之前在公众号有写过。
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> mp;
vector<int> ret;
int nsize = nums.size();
for(int i=0; i<nsize; i++){
mp[nums[i]] = i;
}
for(int i=0; i<nsize; i++){
if(mp.count(target-nums[i]) != 0 && i != mp[target-nums[i]]){
ret.push_back(i);
ret.push_back(mp[target-nums[i]]); // 找到一对返回就行了
return ret;
}
}
return ret;
}
- 有效的字母异位词 leetcode 242 这个也比较简单,第一个字符串每个字符放到map里面++ 第二个字符串每个字符放到map里面--,如果为0了erase掉就行了。
bool isAnagram(string s, string t) {
int ssize = s.size(), tsize = t.size();
if(s.size() != t.size()) return false;
map<char,int> mp;
for(int i=0; i<ssize; i++){
if(mp.count(s[i]) > 0){
mp[s[i]]++;
}else{
mp[s[i]] = 1;
}
}
for(int i=0; i<tsize; i++){
if(mp.count(t[i]) > 0){
mp[t[i]]--;
if(mp[t[i]] == 0){
mp.erase(t[i]);
}
}
else{
return false;
}
}
return mp.empty();
}
中等
- 无重复字符的最长子串 leetcode 3 双指针,一个指向最长子串的左侧,一个指向最长子串的右侧,如果出现了重复的子串,就将左指针指向出现的下一个位置
int lengthOfLongestSubstring(string s) {
map<char, int> mp; // map<char, idx+1>
int ssize = s.size();
int start = 0;
int ret = 0;
for(int i=0; i<ssize; i++){
if(mp.count(s[i]) == 0 || mp[s[i]] < start){ // 没出现过 计算长度 注意这里判断 mp[s[i]] < start
ret = max(ret, i-start+1);
}
else{
start = mp[s[i]]; // 出现过了设置start位置
}
mp[s[i]] = i+1;
}
return ret;
}
- 前K个高频单词 leetcode 692 先统计单词出现的频率,然后用优先队列做最小堆
typedef pair<int, string> PairM;
struct GreaterM{
bool operator()(const PairM& a, const PairM& b){
return (a.first > b.first || (a.first == b.first && a.second < b.second));
}
};
class Solution {
public:
vector<string> topKFrequent(vector<string>& words, int k) {
int wsize = words.size();
map<string, int> mp;
for(int i=0; i<wsize; i++){
mp[words[i]]++;
}
priority_queue<PairM,vector<PairM>,GreaterM> queue;
for(auto &item:mp){
PairM tmp{item.second, item.first};
if(queue.size() < k){
queue.push(tmp);
}
else{
queue.push(tmp);
queue.pop();
}
}
vector<string> ret;
while(!queue.empty()){
ret.push_back(queue.top().second);
queue.pop();
}
reverse(ret.begin(),ret.end());
return ret;
}
};
困难
- 原子的数量 leetcode 726
class Solution {
public:
int index;
bool isUpperCase(const char& c){
return c >= 'A' && c <= 'Z';
}
bool isLowerCase(const char& c){
return c >= 'a' && c <= 'z';
}
bool isNumber(const char& c){
return c >= '0' && c <= '9';
}
string countOfAtoms(string formula) {
auto atomCounter = parse(formula);
string res = "";
for(auto [k,v] : atomCounter){
res += k;
if(v == 1) continue;
res += to_string(v);
}
return res;
}
map<string, int> parse(string formula){
int flen = formula.length();
map<string, int> ret;
while(index < flen && formula[index] != ')'){
if(formula[index] == '('){
index++;
for(auto [k,v] : parse(formula)){
ret[k] += v;
}
}
else{
int start = index;
index++;
while(isLowerCase(formula[index])) index++;
string atomName = formula.substr(start, index-start);
start = index;
while(isNumber(formula[index])) index++;
int num = 1;
if(index > start) num = stoi(formula.substr(start, index-start));
ret[atomName] += num;
}
}
index++;
if(index < flen){
int start = index;
while(isNumber(formula[index])) index++;
int multiFactor = 1;
if(index > start) multiFactor = stoi(formula.substr(start, index-start));
for(auto [k,v]: ret) ret[k] *= multiFactor;
}
return ret;
}
};