原題連結: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;
}