1. 树形算法与回溯算法核心思想解析
树形算法和回溯算法是解决复杂问题的两大利器,它们都基于递归思想,但在应用场景和实现方式上各有侧重。理解这两种算法的核心思想,能够帮助我们高效解决各类数据结构问题。
1.1 树形算法的两种递归范式
树形算法主要分为自顶向下和自底向上两种递归方式:
自顶向下递归:
- 从根节点开始,参数携带信息向下传递
- 适合需要从父节点向子节点传递信息的场景
- 典型应用:路径搜索、状态传递
自底向上递归:
- 从叶子节点开始,通过返回值向上传递信息
- 适合需要汇总子树信息的场景
- 典型应用:子树统计、聚合计算
在实际应用中,我们经常会遇到需要同时使用两种方式的情况。例如在查找最近公共祖先(LCA)问题时,需要自底向上返回节点信息,同时需要自顶向下判断终止条件。
1.2 回溯算法的树形视角
回溯算法本质上是对解空间树的深度优先搜索(DFS),关键点在于:
- 状态维护:当前路径、已用元素等状态需要正确维护
- 剪枝策略:通过条件判断减少不必要的搜索
- 恢复现场:递归返回时需要撤销当前选择,不影响其他分支
回溯算法的核心在于将问题建模为一棵树,每个节点代表一个决策点,分支代表可能的选择。理解这一点,就能将看似复杂的问题转化为树遍历问题。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 树形算法经典问题剖析
2.1 二叉搜索树中第k小元素
2.1.1 中序遍历的三种实现方式
递归解法(全局变量版):
cpp复制int kthSmallest(TreeNode* root, int k) {
int ans = 0, count = 0;
function<void(TreeNode*)> dfs = [&](TreeNode* node) {
if(!node) return;
dfs(node->left);
if(++count == k) ans = node->val;
dfs(node->right);
};
dfs(root);
return ans;
}
这种方法利用中序遍历的特性,在访问节点时计数,简洁明了。
迭代解法(显式栈):
cpp复制int kthSmallest(TreeNode* root, int k) {
stack<TreeNode*> st;
while(root || !st.empty()) {
while(root) {
st.push(root);
root = root->left;
}
root = st.top(); st.pop();
if(--k == 0) return root->val;
root = root->right;
}
return -1;
}
迭代法避免了递归开销,更适合大数据量的情况。
Morris遍历(O(1)空间):
cpp复制int kthSmallest(TreeN
