LeetCodeアルゴリズム問題-Maximum Depth of Binary Tree
4760 ワード
これは悦楽書の164回目の更新で、166編目のオリジナルです
01問題と準備を見る
今日はLeetCodeアルゴリズム問題のEasyレベルの23番目の問題(順位問題番号104)について説明します.ツリーが与えられ、その最大深さが見つかります.最大深さはルートノードから最も遠いリーフノードまでの最長パス上のノード数です.リーフはサブノードのないノードです.
例えば、所与の二叉木[3,9,20,null,null,15,7]は、
深さ=3を返します.
今回の解題で使用される開発ツールはeclipse,jdkで使用されるバージョンは1.8,環境はwin 7 64ビットシステム,Java言語で作成およびテストされる.
02第一の解法
最大深さはルートノードから最も遠いリーフノード経路に含まれるノード数であり,上の二叉木を例にとると,最長経路は3−>20−>15,3−>20−>7の2つであり,この2つの経路のノード数はいずれも3つであるため,最後にその深さは3であると結論した.
特殊な場合1:入力されたツリーが空の場合、ノードはなく、深さは0です.
特殊な場合2:ルートノードのみの場合、その深さは1であり、それ自体のノードは1つしかありません.
通常の状況:簡単なツリーの深さ計算過程を一歩一歩導いてみることができますが、上記のツリーを例に挙げてみましょう.
ルートノードから開始すると、ノード数は1です.ノードが1つしかないためです.
ルートノードのサブノードに入ると、このとき最も長いパスは9という左サブノードと20という右サブノードを計算する最も長いパスであり、明らかに9は葉ノードであり、自分のノードしかない.20は独自のサブノードを持ち,その場合には20からの最長経路を算出する必要がある.
20には左サブノード15,右サブノード7があり,この場合15と7の最長パスを計算し続ける必要があるが,15と7はいずれもリーフノードであるため,ノード数は1のみであり,さらに20ノード自体というルートノードに属するサブノードを加えると,20ノードの最長パスは2である.
同じ3本のノードである2つのサブノード9,20は,サブノード9の最長パス上のノード数が1,サブノード20の最長パス上のノード数が2となり,最大値をとると,さらにルートノード自身のノード数を加えると,1+2=3,3が最長パス上のノード数,すなわちこの二叉木の深さとなる.
ここまで分析すると,ルートノードから最も遠いリーフノードまでのノード数を計算するには,まずその左右のサブノードの最長経路を計算する必要があり,左右のサブノードの最長経路を計算するには,彼ら自身の下の左右のサブノードの最長経路を計算する必要があることが分かった.さらにその最大値を上へ求めます.
03第2の解法
再帰を使うことができる以上、遍歴の方法を使ってみることもできます.ルートノードから開始し、サブノードを上から下に巡回します.これに対して、キューが来ると、巡回するたびにサブノードが格納されます.サブノードの階層を巡回すると、すべてのサブノードが巡回するまで1が加算されます.
特に、内層whileループは、第1の解法と同様に、各層を巡るサブノードである.
04第3の解法
第2の解法の内層サイクルでは、新しいキューを使用して、サイクルごとに入る次の層ノードデータを受信します.変更して、より簡潔にすることができますか?ここではキューのサイズを使用して制御します.ルートノードから、キューに入った後、キューのsizeは1で、内層ループに入り始めます.内層ループが1回歩いた後、キューには2つのサブノードが追加されました.このときのsizeは2で、すべてのサブノードが遍歴するまで、内層ループを開始し続けます.
05検証とテスト
上記の2つの解法について,簡単なツリーを用いてデータテストを行った.
テスト結果は次のとおりです.
テストの結果から、遍歴と再帰は問題を解決できることがわかります.2つ目の解法は、ループを進むたびに新しいオブジェクトを作成するため、メモリと実行時間の消費量が少なくないため、最適化された3つ目の解法が遍歴に適しています.
06小結
以上はすべての内容で、もしみんなが何か良い解法の構想、提案あるいはその他の問題があれば、下の伝言で交流することができて、いいね、伝言、転送は私に対する最大のリターンと支持です!
01問題と準備を見る
今日はLeetCodeアルゴリズム問題のEasyレベルの23番目の問題(順位問題番号104)について説明します.ツリーが与えられ、その最大深さが見つかります.最大深さはルートノードから最も遠いリーフノードまでの最長パス上のノード数です.リーフはサブノードのないノードです.
例えば、所与の二叉木[3,9,20,null,null,15,7]は、
3
/ \
9 20
/ \
15 7
深さ=3を返します.
今回の解題で使用される開発ツールはeclipse,jdkで使用されるバージョンは1.8,環境はwin 7 64ビットシステム,Java言語で作成およびテストされる.
02第一の解法
最大深さはルートノードから最も遠いリーフノード経路に含まれるノード数であり,上の二叉木を例にとると,最長経路は3−>20−>15,3−>20−>7の2つであり,この2つの経路のノード数はいずれも3つであるため,最後にその深さは3であると結論した.
特殊な場合1:入力されたツリーが空の場合、ノードはなく、深さは0です.
特殊な場合2:ルートノードのみの場合、その深さは1であり、それ自体のノードは1つしかありません.
通常の状況:簡単なツリーの深さ計算過程を一歩一歩導いてみることができますが、上記のツリーを例に挙げてみましょう.
ルートノードから開始すると、ノード数は1です.ノードが1つしかないためです.
ルートノードのサブノードに入ると、このとき最も長いパスは9という左サブノードと20という右サブノードを計算する最も長いパスであり、明らかに9は葉ノードであり、自分のノードしかない.20は独自のサブノードを持ち,その場合には20からの最長経路を算出する必要がある.
20には左サブノード15,右サブノード7があり,この場合15と7の最長パスを計算し続ける必要があるが,15と7はいずれもリーフノードであるため,ノード数は1のみであり,さらに20ノード自体というルートノードに属するサブノードを加えると,20ノードの最長パスは2である.
同じ3本のノードである2つのサブノード9,20は,サブノード9の最長パス上のノード数が1,サブノード20の最長パス上のノード数が2となり,最大値をとると,さらにルートノード自身のノード数を加えると,1+2=3,3が最長パス上のノード数,すなわちこの二叉木の深さとなる.
ここまで分析すると,ルートノードから最も遠いリーフノードまでのノード数を計算するには,まずその左右のサブノードの最長経路を計算する必要があり,左右のサブノードの最長経路を計算するには,彼ら自身の下の左右のサブノードの最長経路を計算する必要があることが分かった.さらにその最大値を上へ求めます.
public int maxDepth(TreeNode root) {
if (root == null) {
return 0;
}
int left = maxDepth(root.left);
int right = maxDepth(root.right);
return 1 + Math.max(left, right);
}
03第2の解法
再帰を使うことができる以上、遍歴の方法を使ってみることもできます.ルートノードから開始し、サブノードを上から下に巡回します.これに対して、キューが来ると、巡回するたびにサブノードが格納されます.サブノードの階層を巡回すると、すべてのサブノードが巡回するまで1が加算されます.
public int maxDepth2(TreeNode root) {
if (root == null) {
return 0;
}
int depth = 0;
Queue q = new LinkedList<>();
q.offer(root);
while (!q.isEmpty()) {
Queue tem = new LinkedList<>();
while(!q.isEmpty()){
TreeNode node = q.poll();
if (node.left != null) {
tem.offer(node.left);
}
if (node.right != null) {
tem.offer(node.right);
}
}
q = tem;
depth++;
}
return depth;
}
特に、内層whileループは、第1の解法と同様に、各層を巡るサブノードである.
04第3の解法
第2の解法の内層サイクルでは、新しいキューを使用して、サイクルごとに入る次の層ノードデータを受信します.変更して、より簡潔にすることができますか?ここではキューのサイズを使用して制御します.ルートノードから、キューに入った後、キューのsizeは1で、内層ループに入り始めます.内層ループが1回歩いた後、キューには2つのサブノードが追加されました.このときのsizeは2で、すべてのサブノードが遍歴するまで、内層ループを開始し続けます.
public int maxDepth3(TreeNode root) {
if (root == null) {
return 0;
}
int depth = 0;
Queue q = new LinkedList<>();
q.offer(root);
while (!q.isEmpty()) {
int n = q.size();
while(n-- > 0){
TreeNode node = q.poll();
if (node.left != null) {
q.offer(node.left);
}
if (node.right != null) {
q.offer(node.right);
}
}
depth++;
}
return depth;
}
05検証とテスト
上記の2つの解法について,簡単なツリーを用いてデータテストを行った.
public static void main(String[] args) {
Easy_104_MaximumDepthOfBinaryTree instance = new Easy_104_MaximumDepthOfBinaryTree();
TreeNode t = new TreeNode(1);
TreeNode t2 = new TreeNode(2);
TreeNode t3 = new TreeNode(3);
TreeNode t4 = new TreeNode(4);
TreeNode t5 = new TreeNode(5);
TreeNode t6 = new TreeNode(6);
TreeNode t7 = new TreeNode(7);
TreeNode t8 = new TreeNode(8);
t.left = t2;
t.right = t3;
t2.left = t4;
t2.right = t5;
t3.left = t6;
t3.right = t7;
t7.left = t8;
long start = System.nanoTime();
int result = instance.maxDepth(t);
long end = System.nanoTime();
System.out.println("maxDepth--- :"+result+" , :"+(end-start)/1000+" ");
long start2 = System.nanoTime();
int result2 = instance.maxDepth2(t);
long end2 = System.nanoTime();
System.out.println("maxDepth2--- :"+result2+" , :"+(end2-start2)/1000+" ");
long start3 = System.nanoTime();
int result3 = instance.maxDepth3(t);
long end3 = System.nanoTime();
System.out.println("maxDepth3--- :"+result3+" , :"+(end3-start3)/1000+" ");
}
テスト結果は次のとおりです.
maxDepth--- :4 , :23
maxDepth2--- :4 , :586
maxDepth3--- :4 , :16
テストの結果から、遍歴と再帰は問題を解決できることがわかります.2つ目の解法は、ループを進むたびに新しいオブジェクトを作成するため、メモリと実行時間の消費量が少なくないため、最適化された3つ目の解法が遍歴に適しています.
06小結
以上はすべての内容で、もしみんなが何か良い解法の構想、提案あるいはその他の問題があれば、下の伝言で交流することができて、いいね、伝言、転送は私に対する最大のリターンと支持です!