#include <iostream>
#include <stdio.h>
#include <vector>
#include <string>
#include <queue>
#include <sstream>
using namespace std;
/*
问题:
Given a binary tree, find the maximum path sum.
For this problem, a path is defined as any sequence of nodes from some starting node to any node in the tree along the parent-child connections. The path must contain at least one node and does not need to go through the root.
For example:
Given the below binary tree,
1
/ \
2 3
Return 6.
分析:从二叉树的任意结点开始到某个结点截止的路径,计算路径的最大和。这个好像是程序员面试结点的题目。
一种方法是:维护一个自底向上的到当前结点的路径和,
比如结点:12是叶节点,对应截止到结点12的路径和为12;结点-2,路径和: 12 - 2=10,结点2:需要从左孩子4的截止路径和
和-2的路径和中选择一个较大的,如果两者中较大的都小于0,那么就使路径和为本身,这里为12.
回溯到1,为13。
对于叶节点1,路径和:1,-3:路径和-2
叶节点-1:路径和为-1.2:路径和2,3路径和为:5
对于根节点1,左边路径和为:12,右边路径和为5,选择:左边较大变成:12 , 1 ,5根据最大子数组应该全部链接,
最终结果为18
如果题目是求从任意结点到根节点的最大路径和,那么刚才所讲的方法是可以的,因为每次遇到当前结点,
只需要计算出当前结点左边路径和leftSum,右边路径和rightSum,然后选取最终
tempMax = max(leftSum , rightSum);
maxSum = tempMax > 0 ? (tempMax + value) : value;
其中value是当前结点的值
关键:
1
但是题目现在是求任意结点到任意结点的最大路径和,决策情况变了:
1】要么是从当前结点或者当前结点的左右孩子结点中选择一个最大的连接起来并提供给父节点使用
2】要么是以当前结点来连接左边和右边的子树,作为最终的结果
设左子树路径和为leftSum,右子树路径和为rightSum,当前结点的值为value,提供给上层的结点值为curSum
初始结果result = INT_MIN, tempMax
设minNum=min(leftSum , rightSum),maxNum=max(leftSum , rightSum)
如果左右子树的路径和都小于0,仅仅提供当前结点给父节点使用
1.1】leftSum < 0 && rightSum < 0,curSum=value , tempMax = value,
如果左子树路径和大于0,右子树路径和<0,左子树+当前结点的和提供给父节点使用
1.2】leftSum > 0 && rightSum < 0,curSum= leftSum + value, tempMax = max(leftSum , leftSum + value),
如果右子树路径和>0,左子树路径和<0,右子树+当前结点提供给父节点使用
1.3】leftSum < 0 && rightSum > 0,curSum = rightSum + value, tempMax = max(rightSum , rightSum + value),
如果左子树路径和>0,右子树路径和>0,设较小路径和为min,较大路径和为max
1.4】leftSum > 0 && rightSum > 0,curSum = maxNum + value, tempMax=max(leftSum , rightSum , leftSum + value + rightSum)
result = max(result , tempMax);
问题的关键是如何自底向上,通过递归遍历到叶子结点,就返回结点的值本身;
如果是非叶子结点:返回左右子树中的较大值 + 当前结点值本身,作为路径和,并更新result
2
追忆叶子结点路径和为本身,叶子结点也需要和最大结果比较
if(NULL == root->left && NULL == root->right)
{
_result = max(_result , root->val);//也需要和叶子结点比较,如果只有一个根节点
return root->val;
}
举例:其中N表示空结点
1
2 3
4 -2 -3 2
N N N 12 1 N N -1
输入:
15
1 2 3 4 -2 -3 2 N N N 12 1 N N -1
1
1
2
-12 13
输出:
18
1
13
关键:
1
*/
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
class Solution {
public:
int dfs(TreeNode* root)
{
//空结点路径和为0
if(!root)
{
return 0;
}
//叶子结点路径和为本身,叶子结点也需要和最大结果比较
if(NULL == root->left && NULL == root->right)
{
_result = max(_result , root->val);//也需要和叶子结点比较,如果只有一个根节点
return root->val;
}
//递归遍历左子树和右子树路径和
int leftSum = dfs(root->left);
int rightSum = dfs(root->right);
int maxNum = max(leftSum , rightSum);
int curSum = INT_MIN;
//左右子树路径和都小于0,返回当前结点值为本身
if(leftSum < 0 && rightSum < 0)
{
curSum = root->val;
_result = max(_result , curSum);
}
//左右子树都大于0,
else if(leftSum > 0 && rightSum > 0)
{
curSum = maxNum + root->val;
//最大值可能是直接以当前点连接左右子树的结果
_result = max(_result , leftSum + root->val + rightSum);
}
//左右子树中有1个大于0,
else
{
curSum = maxNum + root->val;
_result = max(_result , curSum);
}
return curSum;
}
int maxPathSum(TreeNode* root) {
_result = INT_MIN;
dfs(root);
return _result;
}
public:
int _result;
};
//构建二叉树,这里默认首个元素为二叉树根节点,然后接下来按照作为每个结点的左右孩子的顺序遍历
//这里的输入是每个结点值为字符串,如果字符串的值为NULL表示当前结点为空
TreeNode* buildBinaryTree(vector<string>& nums)
{
if(nums.empty())
{
return NULL;
}
int size = nums.size();
int j = 0;
//结点i的孩子结点是2i,2i+1
vector<TreeNode*> nodes;
int value;
for(int i = 0 ; i < size ; i++)
{
//如果当前结点为空结点,自然其没有左右孩子结点
if("N" == nums.at(i))
{
nodes.push_back(NULL);
continue;
}
value = atoi(nums.at(i).c_str());
TreeNode* node = new TreeNode(value);
nodes.push_back(node);
}
//设定孩子结点指向,各个结点都设置好了,如果但钱为空结点,就不进行指向
for(int i = 1 ; i <= size ; i++)
{
if(NULL == nodes.at(i-1))
{
continue;
}
if(2 * i <= size)
{
nodes.at(i-1)->left = nodes.at(2*i - 1);
}
if(2*i + 1 <= size)
{
nodes.at(i-1)->right = nodes.at(2*i);
}
}
//设定完了之后,返回根节点
return nodes.at(0);
}
void deleteBinaryTree(TreeNode* root)
{
if(!root)
{
return;
}
if(NULL == root->left && NULL == root->right)
{
delete root;
root = NULL;
}
if(root)
{
deleteBinaryTree(root->left);
deleteBinaryTree(root->right);
}
}
//层序遍历
vector<vector<string>> levelOrder(TreeNode* root) {
vector<vector<string>> results;
if(NULL == root)
{
return results;
}
queue<TreeNode*> nodes;
nodes.push(root);
int size = 1;
int nextSize = 0;
vector<string> result;
TreeNode* node = NULL;
while(!nodes.empty())
{
node = nodes.front();
nodes.pop();
if(node)
{
stringstream stream;
stream << node->val;
result.push_back(stream.str());
}
else
{
result.push_back("N");//表示空结点
}
if(node->left)
{
nodes.push(node->left);
nextSize += 1;
}
if(node->right)
{
nodes.push(node->right);
nextSize += 1;
}
size--;
if(0 == size)
{
size = nextSize;
nextSize = 0;
vector<string> tempResult(result);
results.push_back(tempResult);
result.clear();
}
}
return results;
}
void print(vector<vector<string>>& result)
{
if(result.empty())
{
cout << "no result" << endl;
return;
}
int size = result.size();
int len;
for(int i = 0 ; i < size ; i++)
{
len = result.at(i).size();
for(int j = 0 ; j < len ; j++)
{
cout << result.at(i).at(j) << " " ;
}
cout << endl;
}
cout << endl;
}
void process()
{
vector<string> nums;
string value;
int num;
Solution solution;
vector<vector<string> > result;
while(cin >> num )
{
nums.clear();
for(int i = 0 ; i < num ; i++)
{
cin >> value;
nums.push_back(value);
}
TreeNode* root = buildBinaryTree(nums);
int maxSum = solution.maxPathSum(root);
cout << maxSum << endl;
//打印二叉树中序结点值
//result = levelOrder(root);
//print(result);
deleteBinaryTree(root);
}
}
int main(int argc , char* argv[])
{
process();
getchar();
return 0;
}
leecode 解题总结:124. Binary Tree Maximum Path Sum
最新推荐文章于 2022-12-21 19:11:54 发布