程序员面试金典: 9.4树与图 4.9在二叉树中,打印结点数值总和等于给定值的所有路径

来源:互联网 发布:课程与教学论 知乎 编辑:程序博客网 时间:2024/06/05 02:56
#include <iostream>#include <stdio.h>#include <vector>#include <string>using namespace std;/*问题:给定一颗二叉树,其中每个结点都含有一个数值。设计一个算法,打印结点数值总和等于某个给定值的所有路径。      注意,路径不一定非得从二叉树的根节点或叶节点开始或结束。分析:如果采用暴力破解,对每个结点都去计算路径,判断路径结点值是否等于给定值,则时间复杂度至少为O(N!),这肯定      不行,想到用栈来做,但是对于是否需要设置访问标记无法确定。书上的解法:向上检查是否得到总和。关注“这个结点是否为总和为给定值的某条路径的末端”注意:当找到总和,需要继续访问路径,因为可能存在其他数值总和为0的结点序列输入:7(第一棵树的结点个数n) 12(给定总和)6 3 9 1 4 2 5(第一棵树的所有结点的值,接下来共有n行,每一行表示当前第i个结点对应孩子结点的下标)d(表示有两个孩子结点,后面跟两个孩子结点的下标) 2 3d 4 5 z(无孩子结点)r(只有右孩子结点,后跟右孩子结点下标) 6r 7zz输出:6 3 1 2,3 4 5关键:1 向上检查是否得到总和。关注“这个结点是否为总和为给定值的某条路径的末端”注意:当找到总和,需要继续访问路径,因为可能存在其他数值总和为0的结点序列时间复杂度为O( N log(N) ),n个结点,每个结点平均需要向上计算高度为log(N),//从当前结点开始向上遍历寻找路径,并对其左右孩子递归处理void findSum(TreeNode* head , int sum , vector<int>& vecPath  , int level){if(NULL == head){return;}//将当前结点值插入路径vecPath.push_back(head->_value);//最经典的部分,向上遍历int total = 0;for(int i = level ; i >= 0 ; i--){total += vecPath.at(i);//注意,即使找到,仍然要继续查找,易错if(total == sum){printPath(vecPath , i , level);}}//递归对孩子结点处理findSum(head->_pLeft  , sum , vecPath , level+1);findSum(head->_pRight , sum , vecPath , level+1);//处理完成后,需要将当前结点移除,因为如果是从其他分支结点进入,则当前结点是不需要的,易错vecPath.pop_back();}*/const int MAXSIZE = 10000;typedef struct TreeNode{int _value;TreeNode* _pLeft;TreeNode* _pRight;TreeNode* _pParent;}TreeNode;TreeNode g_treeNodeArray[MAXSIZE];int g_index;TreeNode* createTreeNode(){++g_index;g_treeNodeArray[g_index]._pLeft = g_treeNodeArray[g_index]._pRight = g_treeNodeArray[g_index]._pParent = NULL;return &g_treeNodeArray[g_index];}void buildTree(vector<int>& vecData){if(vecData.empty()){return;}int value ;string childFlag;int leftIndex ;int rightIndex;int size = vecData.size();for(int index = 1 ; index <= size; index++){cin >> childFlag;g_treeNodeArray[index]._value = vecData.at(index-1);if("d" == childFlag){cin >> leftIndex >> rightIndex;g_treeNodeArray[index]._pLeft = &g_treeNodeArray[leftIndex];g_treeNodeArray[leftIndex]._pParent = &g_treeNodeArray[index];g_treeNodeArray[index]._pRight = &g_treeNodeArray[rightIndex];g_treeNodeArray[rightIndex]._pParent = &g_treeNodeArray[index];}else if("l" == childFlag){cin >> leftIndex;g_treeNodeArray[index]._pLeft = &g_treeNodeArray[leftIndex];g_treeNodeArray[leftIndex]._pParent = &g_treeNodeArray[index];}else if("r" == childFlag){cin >> rightIndex;g_treeNodeArray[index]._pRight = &g_treeNodeArray[rightIndex];g_treeNodeArray[rightIndex]._pParent = &g_treeNodeArray[index];}}}int max(int a, int b){return a > b ? a : b;}int getDepth(TreeNode* head){if(NULL == head){return 0;}return max( getDepth(head->_pLeft) , getDepth(head->_pRight) ) + 1;}void printPath(vector<int>& vecPath , int begin , int end){for(int i = begin ; i <= end; i++){cout << vecPath.at(i) << " ";}cout << ",";}//从当前结点开始向上遍历寻找路径,并对其左右孩子递归处理void findSum(TreeNode* head , int sum , vector<int>& vecPath  , int level){if(NULL == head){return;}//将当前结点值插入路径vecPath.push_back(head->_value);//最经典的部分,向上遍历int total = 0;for(int i = level ; i >= 0 ; i--){total += vecPath.at(i);//注意,即使找到,仍然要继续查找,易错if(total == sum){printPath(vecPath , i , level);}}//递归对孩子结点处理findSum(head->_pLeft  , sum , vecPath , level+1);findSum(head->_pRight , sum , vecPath , level+1);//处理完成后,需要将当前结点移除,因为如果是从其他分支结点进入,则当前结点是不需要的,易错vecPath.pop_back();}TreeNode* findRoot(TreeNode* node){if(NULL == node){return NULL;}if(node->_pParent == NULL){return node;}else{return findRoot(node->_pParent);}}void process(){int nodeNum;int sum;vector<int> vecData;int value;while(cin >> nodeNum >> sum){vecData.clear();g_index = 0;for(int i = 0  ; i < nodeNum ; i++){cin >> value;vecData.push_back(value);}buildTree(vecData);TreeNode* root = findRoot(&g_treeNodeArray[1]);int depth = getDepth(root);//寻找路径vector<int> vecPath;findSum(root , sum , vecPath , 0);cout << endl;}}int main(int argc, char* argv[]){process();getchar();return 0;}

0 0
原创粉丝点击