常见二叉树题

// 树的结构
struct TreeNode{
	int val;
	TreeNode *left, *right;
};




树的遍历方法


先序遍历

// 递归
void dfs(TreeNode *p) {
	if (!p) return;
	// 处理当前p节点
	dfs(p->left);
	dfs(p->right);
}

// 迭代
TreeNode *root;
stack<TreeNode*> S;
while (S.size() || root) {
	while (root) {
		S.push(root);
		// 处理当前节点root
		root = root->left;
	}
	root = S.top();
	S.pop();
	root = root->right;
}

中序遍历

// 递归
void dfs(TreeNode *p) {
	if (!p) return;
	dfs(p->left);
	// 处理当前p节点
	dfs(p->right);
}

// 迭代
TreeNode *root;
stack<TreeNode*> S;
while (S.size() || root) {
	while (root) {
		S.push(root);
		root = root->left;
	}
	root = S.top();
	S.pop();
	// 处理当前节点root
	root = root->right;
}

后序遍历

// 递归
void dfs(TreeNode *p) {
	if (!p) return;
	dfs(p->left);
	dfs(p->right);
	// 处理当前p节点
}

// 迭代
if (!root) return;
stack<TreeNode*> S1, S2;
S1.push(root);
while (S1.size()) {
	TreeNode *tmp = S1.top();
	S1.pop();
	S2.push(tmp);
	if (tmp->left)
		S1.push(tmp->left);
	if (tmp->right)
		S1.push(tmp->right);
}
while (!S2.size()) {
	TreeNode* tmp = S2.top();
	S2.pop();
	// 处理当前节点tmp
}
return res;

层次遍历

vector<vector<int>> levelOrder(TreeNode* root) {
    queue<TreeNode*> Q;
    vector<vector<int>> ret;
    if (!root) return ret;
    vector<int> res;
    Q.push(root);
    while (!Q.empty()) {
        int siz = Q.size();
        res.clear();
        while (siz--) {
            TreeNode *tmp = Q.front();
            Q.pop();
            res.push_back(tmp->val);
            if (tmp->left) Q.push(tmp->left);
            if (tmp->right) Q.push(tmp->right);
        }
        ret.push_back(res);
    }
    return ret;
}




二叉搜索树


二叉搜索树的LCA

TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
    TreeNode* ancestor = root;
    while (1) {
        if (p->val < ancestor->val && q->val < ancestor->val) 
            ancestor = ancestor->left;
        else if (p->val > ancestor->val && q->val > ancestor->val) 
            ancestor = ancestor->right;
        else break;
    }
    return ancestor;
}

二叉搜索树全排列

给1~n个节点,求这n个节点生成的二叉搜索树种类

// O(n^2)
int numTrees(int n) {
    vector<vector<int>> dp(n+1, vector<int>(n+1));
    for (int i = 1; i <= n; ++i) 
    	dp[i][i] = 1;
    for (int len = 1; len < n; ++len) {
        for (int i = 1; i <= n-len; ++i) {
            dp[i][i+len] += dp[i][i+len-1] + dp[i+1][i+len];
            for (int j = i+1; j <= i+len-1; ++j) {
                dp[i][i+len] += dp[i][j-1] * dp[j+1][i+len];
            }
        }
    }
    return dp[1][n];
}

// O(n^2)
int numTrees(int n) {
    vector<int> dp(n+1, 1);
    for (int i = 2; i <= n; ++i) {
        dp[i] = 0;
        for (int j = 1; j <= i; ++j) {
            dp[i] += dp[j-1] * dp[i-j];
        }
    }
    return dp[n];
}

// O(n)数学
int numTrees(int n) {
    long long C = 1;
    for (int i = 0; i < n; ++i)
        C = C * 2 * (2 * i + 1) / (i + 2);
    return C;
}

// 输出所有的树
vector<TreeNode*> gettree(int left, int right) {
    if (left > right) return { nullptr };
    vector<TreeNode*> ret;
    for (int i = left; i <= right; ++i) {
        vector<TreeNode*> lson = gettree(left, i-1);
        vector<TreeNode*> rson = gettree(i+1, right);
        for (int x = 0; x < lson.size(); ++x) {
            for (int y = 0; y < rson.size(); ++y) {
                TreeNode *mid = new TreeNode(i);
                mid->left = lson[x];
                mid->right = rson[y];
                ret.push_back(mid);
            }
        }
    }
    return ret;
}
// 题意同上,返回所有二叉搜索树
vector<TreeNode*> generateTrees(int n) {
    return gettree(1, n);
}

恢复二叉搜索树

// 空间复杂度为O(n)的做法
void dfs(TreeNode *p, vector<TreeNode*> &res) {
    if (!p) return;
    dfs(p->left, res);
    res.push_back(p);
    dfs(p->right, res);
}
void recoverTree(TreeNode* root) {
    vector<TreeNode*> res;
    dfs(root, res);
    if (res.size() == 1) return;
    int id1 = -1, id2 = -1;
    for (int i = 0; i < res.size(); ++i) {
        if (!i) {
            if (res[i]->val >= res[i+1]->val) id1 = i;
        }
        else if (i == res.size()-1) {
            if (res[i]->val <= res[i-1]->val) id2 = i;
        }
        else {
            if (res[i]->val <= res[i-1]->val && res[i]->val <= res[i+1]->val 
            || res[i]->val >= res[i-1]->val && res[i]->val >= res[i+1]->val) {
                if (id1 == -1) id1 = i;
                else id2 = i;
            }
        }
    }
    swap(res[id1]->val, res[id2]->val);
}

// Morris中序遍历,空间复杂度为O(1)
void recoverTree(TreeNode* root) {
    TreeNode *x = nullptr, *y = nullptr, *pred = nullptr, *predecessor = nullptr;
    while (root) {
        if (root->left) {
            // predecessor 节点就是当前 root 节点向左走一步,然后一直向右走至无法走为止
            predecessor = root->left;
            while (predecessor->right != nullptr && predecessor->right != root) {
                predecessor = predecessor->right;
            }
            // 让 predecessor 的右指针指向 root,继续遍历左子树
            if (!predecessor->right) {
                predecessor->right = root;
                root = root->left;
            }
            // 说明左子树已经访问完了,我们需要断开链接
            else {
                if (pred && root->val < pred->val) {
                    y = root;
                    if (!x) x = pred;
                }
                pred = root;
                predecessor->right = nullptr;
                root = root->right;
            }
        }
        // 如果没有左孩子,则直接访问右孩子
        else {
            if (pred && root->val < pred->val) {
                y = root;
                if (!x) x = pred;
            }
            pred = root;
            root = root->right;
        }
    }
    swap(x->val, y->val);
}

有序数组转二叉搜索树

TreeNode* dfs(vector<int> &a, int l, int r) {
    if (l > r) 
        return nullptr;
    int m = (l+r)>>1;
    TreeNode *ret = new TreeNode(a[m]);
    ret->left = dfs(a, l, m-1);
    ret->right = dfs(a, m+1, r);
    return ret;
}
TreeNode* sortedArrayToBST(vector<int>& nums) {
    TreeNode *ret = new TreeNode();
    ret = dfs(nums, 0, nums.size()-1);
    return ret;
}

有序链表转二叉搜索树

// 每次都要跑一次快慢指针获取中值,时间复杂度O(nlogn),空间复杂度O(nlogn)
ListNode* getMedian(ListNode* left, ListNode* right) {
    ListNode* fast = left;
    ListNode* slow = left;
    while (fast != right && fast->next != right) {
        fast = fast->next;
        fast = fast->next;
        slow = slow->next;
    }
    return slow;
}
TreeNode* buildTree(ListNode* left, ListNode* right) {
    if (left == right) {
        return nullptr;
    }
    ListNode* mid = getMedian(left, right);
    TreeNode* root = new TreeNode(mid->val);
    root->left = buildTree(left, mid);
    root->right = buildTree(mid->next, right);
    return root;
}
TreeNode* sortedListToBST(ListNode* head) {
    return buildTree(head, nullptr);
}


// 中序遍历优化,时间复杂度O(n),空间复杂度O(logn)
int getLength(ListNode* head) {
    int ret = 0;
    for (; head != nullptr; ++ret, head = head->next);
    return ret;
}
TreeNode* buildTree(ListNode*& head, int left, int right) {
    if (left > right) {
        return nullptr;
    }
    int mid = (left + right + 1) / 2;
    TreeNode* root = new TreeNode();
    root->left = buildTree(head, left, mid - 1);
    root->val = head->val;
    head = head->next;
    root->right = buildTree(head, mid + 1, right);
    return root;
}
TreeNode* sortedListToBST(ListNode* head) {
    int length = getLength(head);
    return buildTree(head, 0, length - 1);
}

二叉搜索树中第k小的节点

int kthSmallest(TreeNode* root, int k) {
    stack<TreeNode*> S;
    while (S.size() || root) {
        while (root) {
            S.push(root);
            root = root->left;
        }
        root = S.top();
        S.pop();
        if (--k == 0) break;
        root = root->right;
    }
    return root->val;
}




判断二叉树

验证二叉搜索树

bool is(TreeNode *p, long long minn, long long maxn) {
    if (!p) return 1;
    if (p->val <= minn || p->val >= maxn) return 0;
    return (is(p->left, minn, p->val) && is(p->right, p->val, maxn));
}
// 判断该二叉树是否为二叉搜索树
bool isValidBST(TreeNode* root) {
    return is(root, LONG_MIN, LONG_MAX);
}

判断对称二叉树

// 递归
bool is(TreeNode *a, TreeNode *b) {
    if (!a && !b) return 1;
    if (!a || !b) return 0;
    return (a->val == b->val && is(a->left, b->right) && is(a->right, b->left));
}
// 给定一棵二叉树,判断是否为镜像树
bool isSymmetric(TreeNode* root) {
    if (!root) return root;
    return is(root->left, root->right);
}


// 迭代
bool check(TreeNode *u, TreeNode *v) {
    queue <TreeNode*> q;
    q.push(u); q.push(v);
    while (!q.empty()) {
        u = q.front(); q.pop();
        v = q.front(); q.pop();
        if (!u && !v) continue;
        if ((!u || !v) || (u->val != v->val)) 
        	return false;
        q.push(u->left); 
        q.push(v->right);
        q.push(u->right); 
        q.push(v->left);
    }
    return true;
}
bool isSymmetric(TreeNode* root) {
    return check(root, root);
}

判断平衡二叉树

// O(n^2)
int gdep(TreeNode *p) {
    if (!p) return 0;
    return max(gdep(p->left), gdep(p->right)) + 1;
}
bool isBalanced(TreeNode* root) {
    if (!root) return true;
    return (abs(gdep(root->left)-gdep(root->right)) <= 1) && isBalanced(root->left) && isBalanced(root->right);
}

// O(n)
int get_dep(TreeNode* root) {
    if (!root) return 0;
    int l_dep = get_dep(root->left);
    int r_dep = get_dep(root->right);
    if (l_dep < 0 || r_dep < 0 || abs(l_dep - r_dep) > 1)
        return -1;
    return max(l_dep, r_dep) + 1;
}

bool isBalanced(TreeNode* root) {
    return get_dep(root) >= 0;
}

判断两棵树是否相同

bool isSameTree(TreeNode* p, TreeNode* q) {
    if (!p && !q) return 1;
    if (!p || !q) return 0;
    return (p->val==q->val 
    		&& isSameTree(p->left, q->left) 
    		&& isSameTree(p->right, q->right));
}

判断两棵树是否互为子树

约定空树不是任意一个树的子结构

bool issub(TreeNode* A, TreeNode* B) {
    if (!B) return true;
    if (!A) return false;
    if (A->val == B->val) return issub(A->left, B->left) && issub(A->right, B->right);
    return false;
}
bool isSubStructure(TreeNode* A, TreeNode* B) {
    if (!A || !B) return false;
    if (issub(A, B)) return true;
    return isSubStructure(A->left, B) || isSubStructure(A->right, B);
}




构造二叉树

前序、中序构造二叉树

TreeNode* build(vector<int>&pre, int pl, int pr, vector<int>&in, int il, int ir, map<int, int>&m) {
    if (pl > pr || il > ir) return nullptr;
    TreeNode *ret = new TreeNode(pre[pl]);
    int mid = m[pre[pl]];
    ret->left  = build(pre, pl+1, pl+mid-il, in, il, mid-1, m);
    ret->right = build(pre, pl+mid-il+1, pr, in, mid+1, ir, m);
    return ret;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
    map<int, int> m;
    for (int i = 0; i < inorder.size(); ++i) 
        m[inorder[i]] = i;
    return build(preorder, 0, preorder.size()-1, inorder, 0, inorder.size()-1, m);
}

中序、后续构造二叉树

TreeNode* build(vector<int>&pos, int pl, int pr, vector<int>&in, int il, int ir, map<int, int>&m) {
    if (pl > pr || il > ir) return nullptr;
    TreeNode *ret = new TreeNode(pos[pr]);
    int mid = m[pos[pr]];
    ret->left  = build(pos, pl, pl+mid-il-1, in, il, mid-1, m);
    ret->right = build(pos, pl+mid-il, pr-1, in, mid+1, ir, m);
    return ret;
}
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
    map<int, int> m;
    for (int i = 0; i < inorder.size(); ++i) 
        m[inorder[i]] = i;
    return build(postorder, 0, postorder.size()-1, inorder, 0, inorder.size()-1, m);
}

二叉树先序展开为链表

直接前序遍历就行,这里展示nb一点的解法

void flatten(TreeNode* root) {
    if (!root) return;
    TreeNode *next, *pre;
    while (root) {
        if (root->left) {
            next = root->left;
            pre = next;
            while (pre->right) 
                pre = pre->right;
            if (root->right) 
                pre->right = root->right;
            root->left = nullptr;
            root->right = next;
        }
        root = root->right;
    }
}

轴对称翻转二叉树

将树轴对称翻转

TreeNode* dfs(TreeNode*&p) {
    if (!p) return nullptr;
    TreeNode *l = dfs(p->left);
    TreeNode *r = dfs(p->right);
    p->left = r;
    p->right = l;
    return p;
}
TreeNode* invertTree(TreeNode* root) {
    dfs(root);
    return root;
}

根节点最大二叉树

每次选取数组中最大值作为根节点,递归处理左边数字和右边数字

// 递归 O(n^2)
TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
    if (!nums.size()) return nullptr;
    auto mid = max_element(nums.begin(), nums.end());
    vector<int> leftPart(nums.begin(), mid);
    vector<int> rightPart(mid + 1, nums.end());
    TreeNode* root = new TreeNode(*mid);
    root -> left = constructMaximumBinaryTree(leftPart);
    root -> right = constructMaximumBinaryTree(rightPart);
    return root;
}

// 单调栈 O(n)
TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
    stack<TreeNode*> nodes;
    TreeNode* curNode = nullptr;
    for (int i=0; i < nums.size(); ++i) { 
        curNode = new TreeNode(nums[i]);
        while (!nodes.empty() && nodes.top()->val < curNode->val) { 
            TreeNode* top = nodes.top();  
            nodes.pop();
            if (!nodes.empty() && nodes.top()->val < curNode->val) 
                nodes.top()->right = top;
            else  
                curNode->left = top;  
        }
        nodes.push(curNode);
    }
    while (!nodes.empty()) { 
        curNode = nodes.top(); 
        nodes.pop();
        if (!nodes.empty()) 
            nodes.top()->right = curNode;
    }
    return curNode;
}

序列化与反序列化二叉树

void rserialize(TreeNode* root, string& str) {
    if (root == nullptr) {
        str += "None,";
    } else {
        str += to_string(root->val) + ",";
        rserialize(root->left, str);
        rserialize(root->right, str);
    }
}

string serialize(TreeNode* root) {
    string ret;
    rserialize(root, ret);
    return ret;
}

TreeNode* rdeserialize(list<string>& dataArray) {
    if (dataArray.front() == "None") {
        dataArray.erase(dataArray.begin());
        return nullptr;
    }

    TreeNode* root = new TreeNode(stoi(dataArray.front()));
    dataArray.erase(dataArray.begin());
    root->left = rdeserialize(dataArray);
    root->right = rdeserialize(dataArray);
    return root;
}

TreeNode* deserialize(string data) {
    list<string> dataArray;
    string str;
    for (auto& ch : data) {
        if (ch == ',') {
            dataArray.push_back(str);
            str.clear();
        } else {
            str.push_back(ch);
        }
    }
    if (!str.empty()) {
        dataArray.push_back(str);
        str.clear();
    }
    return rdeserialize(dataArray);
}




二叉树求解


二叉树的直径

int maxd=0;
int diameterOfBinaryTree(TreeNode* root) {
    depth(root);
    return maxd;
}
int depth(TreeNode* node) {
    if (node == null) return 0;
    int Left = depth(node.left);
    int Right = depth(node.right);
    maxd = max(Left+Right, maxd);
    return max(Left, Right)+1;
}

二叉树最大深度

从根节点到最深的叶子节点距离

void dfs(TreeNode *p, int dep, int &ret) {
    if (p) ret = max(ret, dep);
    else return;
    dfs(p->left, dep+1, ret);
    dfs(p->right, dep+1, ret);
}
// 距离根节点最远的叶子节点的距离
int maxDepth(TreeNode* root) {
    if (!root) return 0;
    int ret = 0;
    dfs(root, 1, ret);
    return ret;
}

二叉树最小深度

从根节点到最浅的叶子节点距离

int minDepth(TreeNode* root) {
    queue<TreeNode*> q;
    if (!root) return 0;
    q.push(root);
    int ret = 0;
    while (!q.empty()) {
        int siz = q.size();
        ret++;
        while (siz--) {
            TreeNode *tmp = q.front();
            q.pop();
            if (tmp->left) q.push(tmp->left);
            if (tmp->right) q.push(tmp->right);
            if (!tmp->left && !tmp->right) 
            	return ret;
        }
    }
    return ret;
}

二叉树最大路径

从任意节点出发,到任意节点,至少包含一个节点

int maxGain(TreeNode *p, int &ret) {
	if (!p) return 0;
	int leftGain = max(maxGain(p->left, ret), 0);
	int rightGain = max(maxGain(p->right, ret), 0);
	int priceNewpath = p->val + leftGain + rightGain;
	ret = max(ret, priceNewpath);
	return p->val + max(leftGain, rightGain);
}
int maxPathSum(TreeNode* root) {
	int ret = INT_MIN;
	maxGain(root, ret);
	return ret;
}

二叉树路径总和

判断根节点到叶子节点的和是否等于特定值sum

// DFS
bool hasPathSum(TreeNode *root, int sum) {
    if (root == nullptr) {
        return false;
    }
    if (root->left == nullptr && root->right == nullptr) {
        return sum == root->val;
    }
    return hasPathSum(root->left, sum - root->val) ||
           hasPathSum(root->right, sum - root->val);
}

// BFS
bool hasPathSum(TreeNode *root, int sum) {
    if (root == nullptr) {
        return false;
    }
    queue<TreeNode*> que_node;
    queue<int> que_val;
    que_node.push(root);
    que_val.push(root->val);
    while (!que_node.empty()) {
        TreeNode *now = que_node.front();
        int temp = que_val.front();
        que_node.pop();
        que_val.pop();
        if (now->left == nullptr && now->right == nullptr) {
            if (temp == sum) {
                return true;
            }
            continue;
        }
        if (now->left != nullptr) {
            que_node.push(now->left);
            que_val.push(now->left->val + temp);
        }
        if (now->right != nullptr) {
            que_node.push(now->right);
            que_val.push(now->right->val + temp);
        }
    }
    return false;
}

输出路径

// DFS
vector<vector<int>> ret;
vector<int> path;
void dfs(TreeNode* root, int targetSum) {
    if (root == nullptr) {
        return;
    }
    path.emplace_back(root->val);
    targetSum -= root->val;
    if (root->left == nullptr && root->right == nullptr && targetSum == 0) {
        ret.emplace_back(path);
    }
    dfs(root->left, targetSum);
    dfs(root->right, targetSum);
    path.pop_back();
}
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
    dfs(root, targetSum);
    return ret;
}

输出路径数

// DFS
int rootSum(TreeNode* root, int targetSum) {
    if (!root) return 0;
    int ret = root->val == targetSum;
    ret += rootSum(root->left, targetSum - root->val);
    ret += rootSum(root->right, targetSum - root->val);
    return ret;
}
int pathSum(TreeNode* root, int targetSum) {
    if (!root) return 0;
    return rootSum(root, targetSum) + pathSum(root->left, targetSum) + pathSum(root->right, targetSum);
}


// 前缀和
unordered_map<long long, int> prefix;
int dfs(TreeNode *root, long long curr, int targetSum) {
    if (!root)  return 0;
    int ret = 0;
    curr += root->val;
    if (prefix.count(curr - targetSum)) {
        ret = prefix[curr - targetSum];
    }
    prefix[curr]++;
    ret += dfs(root->left, curr, targetSum);
    ret += dfs(root->right, curr, targetSum);
    prefix[curr]--;
    return ret;
}
int pathSum(TreeNode* root, int targetSum) {
    prefix[0] = 1;
    return dfs(root, 0, targetSum);
}

二叉树的LCA

// 获取从根节点到两个节点的路径,然后判断最早分岔的点
void dfs(TreeNode* p, TreeNode *targe, vector<TreeNode*> &s) {
    if (s.size() && s.back() == targe) return;
    if (p) {
        s.push_back(p);
        dfs(p->left, targe, s);
        dfs(p->right, targe, s);
        if (s.back() != targe) s.pop_back();
    }
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
    vector<TreeNode*> s1, s2;
    dfs(root, p, s1);
    dfs(root, q, s2);
    for (int i = (int)(min(s1.size(), s2.size())-1); i >= 0; --i) 
        if (s1[i] == s2[i]) 
        return s1[i];
    return root;
}


// DFS
bool dfs(TreeNode* root, TreeNode* p, TreeNode* q, TreeNode* &ans) {
    if (root == nullptr) return false;
    bool lson = dfs(root->left, p, q, ans);
    bool rson = dfs(root->right, p, q, ans);
    if ((lson && rson) || ((root->val == p->val || root->val == q->val) && (lson || rson))) {
        ans = root;
    } 
    return lson || rson || (root->val == p->val || root->val == q->val);
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
	TreeNode* ans;
    dfs(root, p, q);
    return ans;
}


// hash
void dfs(TreeNode* root, unordered_map<int, TreeNode*> &fa, unordered_map<int, bool> &vis){
    if (root->left != nullptr) {
        fa[root->left->val] = root;
        dfs(root->left, fa, vis);
    }
    if (root->right != nullptr) {
        fa[root->right->val] = root;
        dfs(root->right, fa, vis);
    }
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
    unordered_map<int, TreeNode*> fa;
    unordered_map<int, bool> vis;
    fa[root->val] = nullptr;
    dfs(root, fa, vis);
    while (p != nullptr) {
        vis[p->val] = true;
        p = fa[p->val];
    }
    while (q != nullptr) {
        if (vis[q->val]) return q;
        q = fa[q->val];
    }
    return nullptr;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值