CSP歷年複賽題-P5018 [NOIP2018 普及組] 對稱二叉樹

五月江城發表於2024-06-11

原題連結:https://www.luogu.com.cn/problem/P5018

題意解讀:找到是對稱二叉樹的最大子樹節點數。

解題思路:

1、先統計每一個節點為子樹的節點數

int dfs1(int root)
{
    if(root == -1) return 0;
    return cnt[root] = dfs1(tree[root].l) + dfs1(tree[root].r) + 1;
}

2、再從根依次向下列舉每一個子節點,判斷左右子樹是否對稱,如果對稱則輸出子樹節點數,否則遞迴從左、右子樹中找最大的對稱子樹節點數

int dfs2(int root)
{
    if(root == -1) return 0;
    if(check(tree[root].l, tree[root].r)) return cnt[root];
    else return max(dfs2(tree[root].l), dfs2(tree[root].r));
}

3、檢查一個節點的左、右子樹是否對稱

如果左、右子樹的根都是-1,則是對稱

如果左、右子樹節點數不相等,肯定不對稱

如果左、右子樹根節點權值不相等,肯定不對稱

遞迴判斷左子樹的左子樹是否和右子樹的右子樹對稱,左子樹的右子樹是否和右子樹的左子樹對稱

bool check(int left, int right)
{
    //左右都是空,只有根節點,也是對稱的
    if(left == -1 && right == -1) return true;
    //左右子樹節點數不一樣,肯定不對稱
    if(cnt[left] != cnt[right]) return false;
    //左右節點權值不同,也不對稱
    if(tree[left].w != tree[right].w) return false;
    //遞迴判斷左-左、右-右,左-右、右-左是否對稱
    return check(tree[left].l, tree[right].r) && check(tree[left].r, tree[right].l);
}

時間複雜度分析:列舉每一個節點複雜度是n,如果從某個節點開始是對稱,則需要遞迴logn次,總體複雜度n*logn

100分程式碼:

#include <bits/stdc++.h>
using namespace std;

const int N = 1000005;
int n;

struct node
{
    int l, r, w;
} tree[N];

int cnt[N]; //以每個節點為根的子樹的節點數

//統計所有節點為根的子樹的節點數
int dfs1(int root)
{
    if(root == -1) return 0;
    return cnt[root] = dfs1(tree[root].l) + dfs1(tree[root].r) + 1;
}

//檢查以left,right為根的子樹是否對稱
bool check(int left, int right)
{
    //左右都是空,只有根節點,也是對稱的
    if(left == -1 && right == -1) return true;
    //左右子樹節點數不一樣,肯定不對稱
    if(cnt[left] != cnt[right]) return false;
    //左右節點權值不同,也不對稱
    if(tree[left].w != tree[right].w) return false;
    //遞迴判斷左-左、右-右,左-右、右-左是否對稱
    return check(tree[left].l, tree[right].r) && check(tree[left].r, tree[right].l);
}

//列舉所有點,看左右是否對稱,返回對稱的最大子樹節點數
int dfs2(int root)
{
    if(root == -1) return 0;
    if(check(tree[root].l, tree[root].r)) return cnt[root];
    else return max(dfs2(tree[root].l), dfs2(tree[root].r));
}

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i++)
    {
        cin >> tree[i].w;
    }
    for(int i = 1; i <= n; i++)
    {
        cin >> tree[i].l >> tree[i].r;
    }

    dfs1(1);
    cout << dfs2(1);

    return 0;
}

相關文章