548 - Tree

Problem.png

給出一棵樹的中序和后序遍歷,問從根到哪個葉結(jié)點的權(quán)值累加和最大。
已知二叉樹的中序和后序,可以構(gòu)造出這棵二叉樹,然后遞歸深搜這棵樹,比較每條路徑的累加權(quán)值即可。


#include <iostream>
#include <string>
#include <sstream>
using namespace std;

const int maxv = 10000 + 10;

int in_order[maxv], post_order[maxv], lch[maxv] = {0}, rch[maxv] = {0};
int n;

bool read_list(int* a) {
    string line;
    if (!getline(cin, line)) return false;
    stringstream ss(line);
    int val;
    n = 0;
    while (ss >> val) {
        a[n] = val;
        n++;
    }
    return true;
}

/**
 * in_order[L1...R1]是當(dāng)前這棵樹的中序
 * post_order[L2...R2]是當(dāng)前這棵樹的后序
 * 算法的主題思想是通過后序的最后一個值找到當(dāng)前這棵樹的根
 * 然后在中序中找到根的位置,則左側(cè)為左子樹的中序,右側(cè)為右子樹的中序
 * 再根據(jù)左子樹的結(jié)點個數(shù)找出左子樹的后序和右子樹的后序
 * 之后再分別對左子樹和右子樹進(jìn)行遞歸,得到當(dāng)前根的左孩子和右孩子,完成建樹
**/
int build(int L1, int R1, int L2, int R2) {
    if (L1 > R1) return 0;  // 遞歸到空樹時結(jié)束遞歸
    int root = post_order[R2];
    int p = L1;
    while (in_order[p] != root) {
        p++;
    }
    int lcnt = p - L1;    // 左子樹的結(jié)點個數(shù)
    // lpost L2, L2 + lcnt - 1
    // rpost L2 + lcnt, R2 - 1
    lch[root] = build(L1, p - 1, L2, L2 + lcnt - 1);
    rch[root] = build(p + 1, R1, L2 + lcnt, R2 - 1);
    return root;
}

int best, best_sum;

// 深度優(yōu)先搜索,不斷累加權(quán)值
// 因為是遞歸,所以權(quán)值要作為參數(shù)
void dfs(int u, int sum) {
    sum += u;
    if (!lch[u] && !rch[u]) {
        if (sum < best_sum || (sum == best_sum && u < best)) {
            best = u;
            best_sum = sum;
        }
    }
    if (lch[u]) dfs(lch[u], sum); // 有左子樹就遞歸搜索一下左子樹
    if (rch[u]) dfs(rch[u], sum); // 有右子樹就遞歸搜索一下右子樹
}

int main() {
    while (read_list(in_order)) {
        read_list(post_order);
        int root;
        root = build(0, n - 1, 0, n - 1);
        best_sum = 10000000;
        dfs(root, 0);
        cout << best << endl;
    }
    return 0;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容