直接問題についてあまり話さないでください= =
1.再帰
タイトルから、サブツリーはルートノードとリーフノード、またはノードのいずれかであることがわかります。タイトルの対称バイナリツリーは、ツリーの最下部までルートノードで構成される必要があるツリーです。
これは単純で、再帰的な方法を簡単に考えることができます
1.ルートノードの列挙、2つの左と右の子ノードが決定される 是否存在
と是否相等
、本、と等しい権利の点は、再帰が持っている場合 。左右两个孩子节点
左右两个孩子节点
上記の判断を繰り返します。
2.対称二分木を判定した後、ノードをルートノードとして対称二分木のノード数を計算し、最適値を取得できます。
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; #define N 1e6 + 10; // もちろん、const int v [N]、l [N]、r [N]; // v [i]:ノードiの重み; l [i]:ノードiの左の子の数; r [i]:ノードiの右の子数値 int n、ans = 0 ; bool pd; // 対称バイナリツリーであるかどうかを判断する int cnt(int x){ // xをルートノードとする対称バイナリツリーのノード数を計算する int sum 0 ; if( l [x]!= -1)合計+ =cnt(l [x]); if(r [x]!= -1)sum + = cnt(r [x]); return sum + 1 ; // ルートノードを計算する } void check(int x、int y){ // 判定対称2分岐ツリー if(x ==- 1 && y ==- 1)return ; // 最終終了 if(x ==- 1 || y ==- 1 || v [x]!= V [y]){ // 非対称 pd = false ; return ; } check(l [x]、r [y]); check(r [x]、l [y]); } intmain(){ cin >> n; for(int i = 1 ; i <= n; ++ i) cin >> v [i]; for(int i = 1 ; i <= n; ++ i) cin >> l [i] >> r [i]; ans = 1 ; //(int i = 1 ; i <= n; ++ i){ // 対称性2を列挙するための少なくとも1つの対称性(1ノード) フォークツリーのルートノードif(l [i]!= -1 && r [i]!= -1 && v [l [i]] == pd = true ; // v [rの [i]]){まず、デフォルトは対称二分木 チェック(l [i]、r [i]); if (pd) ans = max(ans、cnt(i)); // 対称二分木である場合、ノードの数を計算できます最大を取る } } cout << ans; return 0 ; }
check(l [x]、r [y]);
check(r [x]、l [y]);
対称二分木を判断するとき、それは鏡面対称でなければなりません
だからチェックするときに対称性をミラーリングする
2dfs
二分木が対称である場合、同じ深さの2つのノードu 、vに対して、lson(u)l s o n (u )およびrson(v)r s o n (v )、rson(u)rが必要ですs o n (u )およびlson(v)l s o n (v )、およびval_u = val_v:
int read()
{
int x = 0、f = 1;
char ch = getchar();
while( '0'> ch || '9' <ch){
if(ch == '-')
f = -1 ;
ch = getchar();
} //正と負の
while( '0' <= ch <= '9'){
x = x * 10 + ch-48;
ch = getchar();
} // Add
return x * f;
}
int n、son [1000050] [2]、val [1000050]、size [1000050];
// son [i] [0]はiの左側の息子です
// son [i] [1 ]はiの右の息子です
void dfs(int u)//左から右にスイープ
{
size [u] = 1;
if(son [u] [0]!= -1)
{
dfs(son [u] [0 ]);
size [u] + = size [son [u] [0]]; //サイズは、次のステップに入る前に現在の状態を変更しますdfs
}
if(son [u] [1]!= -1)
{
dfs (息子[u] [1]);
サイズ[u] + =サイズ[息子[u] [1]];
}
}
bool check(int u、int v)
{
if(u ==-1 && v ==-1)//特判
return true;
if(u!=-1 && v!=-1 && val [u] == val [v] && check(son [u] [0]、son [v] [1])&& check(son [u] [1]、son [ v] [0]))
trueを返します。
falseを返します。
}
int main()
{
n = read();
for(int i = 1; i <= n; i ++)
val [i] = read();
for(int i = 1; i <= n; i ++)
{
son [i] [0] = read();
son [i] [1] = read();
}
dfs(1);
int ans = 0;
for(int i = 1; i <= n; i ++)
if(check(son [i] [0]、son [i] [1]))
ans = max(ans、size [i]);
cout << ans << endl;
0を返します。
}
しかし、この爆発に近い検索は再帰ほどよくなく、私にとってはかなり難しいと思います
3.ハッシュ
ツリーの形式を直接ハッシュすることができます。つまり、中位トラバーサル1(高度な左サブツリー)と中位トラバーサル2(高度な右サブツリー)を分割してハッシュ値を記録できます。各ノードについて、ノードの左側の息子の中位トラバーサル1のハッシュ値は、右の息子の中位トラバーサル2のハッシュ値と同じです。これは、この点をルートとするツリーが対称であることを示しています(ただし、再帰的に==渡したため、ハッシュはコードにヒットしませんでした==)