diff --git a/src/bin/step1.rs b/src/bin/step1.rs new file mode 100644 index 0000000..54ec889 --- /dev/null +++ b/src/bin/step1.rs @@ -0,0 +1,311 @@ +// Step1 +// 目的: 方法を思いつく + +// 方法 +// 5分考えてわからなかったら答えをみる +// 答えを見て理解したと思ったら全部消して答えを隠して書く +// 5分筆が止まったらもう一回みて全部消す +// 正解したら終わり + +/* + 問題の理解 + - 二分探索木の根であるrootと整数vが与えられる。 + あるノードから見た時に左側のサブツリーにはノード自身が持つ値より小さい値を持つノードで構成される + あるノードから見た時に右側のサブツリーにはノード自身が持つ値より大きい値を持つノードで構成される + 整数v以下のノードで構成されるツリーと整数vを超えるノードで構成されるツリーに分割する。 + 分割したサブツリーうちノード数が多い方のサブツリーを返す。サブツリーの数が同じ場合はrootノードの値が大きい方のサブツリーを返す。 + + 何を考えて解いていたか + - テストについて。 + - 採点システムがRustに対応していないので、テストコードの実装を行う。過去に二分探索木の問題を解いたときのヘルパーメソッドが流用できそうだが、折角なので練習として再度書いてみる。 + - 配列から二分探索木を構築するヘルパーメソッドを実装する必要がある。 + - 二分探索木から配列を構築するヘルパーメソッドを実装する必要がある。 + - 問題の解法について。 + - サブツリーに含まれるノードの数を数える必要がある。サブツリーのルートノードを入力としてノードの数を返す処理が必要。 + - もしかすると、サブツリーに分割する時点でどちらのサブツリーの方がノードの数が多いか分かる方法があるかも知れないが思いつかない。 + - vを境界にして分割する方法が思いつかない。 + 手が止まったので解答をみる。 + + 何がわからなかったか + - ノードを分割する手順。あるノードの値がv以下で、このノードの子の値がv以上のときにどういう手順でノードを入れ替えるのかがうまく言語化できない。 + + 解法の理解(GPT-5.2の出力コードを自分で理解しやすいようにリファクタリングした) + - 概要 + - 整数vを境界として、二分探索木を2つの二分探索木に分割する。(node.val <= v, v < node.val) + - 再帰の処理内容 + - base_case + - ノードがNoneであれば、子ノードも存在しないので、(None,None)を返すことで、見るべきサブツリーが存在しないことを表現する。 + - recursive_case + - v以下の値を持つノードから構成されるサブツリー(left_subtree)、vを超える値を持つノードから構成されるサブツリー(right_subtree)を作りたいという気持ち。 + - ノードの値がv以下のとき + - 左の子ノードが存在するとき、v以下である値を持つことは確定しているので、未確定な右の子ノードを取り出してrecursive_caseに入る + - 二分探索木なので、あるノードの左の子ノードは親ノードより小さい値を持つ + - recursive_caseから得られたv以下の値から構成されるleft_subtreeをnode.rightに設定する。 + - ノードの値がvを超えるとき + - 右の子ノードが存在するとき、vを超える値を持つことは確定しているので、未確定な左の子ノードを取り出してrecursive_caseに入る + - 二分探索木なので、あるノードの右の子ノードは親ノードより大きい値を持つ + - recursive_caseから得られたvを超える値から構成されるright_subtreeをnode.leftに設定する。 + + 所感 + - GPT-5.2のコードがかなり読みづらかったので、これを読みながら自分なりに読みやすくリファクタリングする作業が理解を進めるよい練習になった。 + - GPT-5.2のコードでは二分探索木の分割をしながら、ノードの数え上げも行っていたので読みづらかったが、プロコン文脈でパフォーマンスを取るならそっちの方が良いことは理解できる。 + 一方で、自分の実装のほうが可読性が優れていると考える。ノードの数え上げと分割をそれぞれ分離できているため。 + - 時間計算量の観点では、ワンパスでできるかどうかなので、プロコン文脈でなければ自分の実装で良いと考えた。 + 最適化するのであれば、ノードの数え上げ処理をループによる実装に書き換えて再帰処理による関数呼び出しのオーバーヘッドを削減する。 + - ループでの実装も練習する。 +*/ + +use std::{cell::RefCell, rc::Rc}; + +#[derive(PartialEq, Debug)] +pub struct TreeNode { + val: u32, + left: Option>>, + right: Option>>, +} +impl TreeNode { + pub fn build_node(val: u32) -> Rc> { + Rc::new(RefCell::new(TreeNode::new(val))) + } + + pub fn count_nodes(&self) -> usize { + fn count_node(node: &Option>>) -> usize { + match node { + None => 0, + Some(node) => { + let node = node.borrow(); + 1 + count_node(&node.left) + count_node(&node.right) + } + } + } + + 1 + count_node(&self.left) + count_node(&self.right) + } + + fn new(val: u32) -> Self { + Self { + val, + right: None, + left: None, + } + } +} + +pub struct Solution {} +impl Solution { + pub fn split_b_s_t(root: Rc>, v: u32) -> Rc> { + let (left_tree, right_tree) = Self::split_tree(Some(root), v); + + let (left_tree, right_tree) = match (left_tree, right_tree) { + (Some(l), None) => return l, + (None, Some(r)) => return r, + (Some(l), Some(r)) => (l, r), + (None, None) => unreachable!(), + }; + + let (left_node_count, right_node_count) = ( + left_tree.borrow().count_nodes(), + right_tree.borrow().count_nodes(), + ); + if left_node_count < right_node_count { + return right_tree; + } else if right_node_count < left_node_count { + return left_tree; + }; + + if left_tree.borrow().val < right_tree.borrow().val { + return right_tree; + } + + left_tree + } + + fn split_tree( + node: Option>>, + v: u32, + ) -> (Option>>, Option>>) { + match node { + None => (None, None), + Some(node) => { + let node_val = node.borrow().val; + + if node_val <= v { + let right_node = node.borrow_mut().right.take(); + let (left_subtree, right_subtree) = Self::split_tree(right_node, v); + + node.borrow_mut().right = left_subtree; + + (Some(node), right_subtree) + } else { + let left_node = node.borrow_mut().left.take(); + let (left_subtree, right_subtree) = Self::split_tree(left_node, v); + + node.borrow_mut().left = right_subtree; + + (left_subtree, Some(node)) + } + } + } + } +} + +#[cfg(test)] +mod tests { + use std::collections::VecDeque; + + use super::*; + + fn to_binary_search_tree(node_values: &Vec>) -> Rc> { + let get_node_value = |i: usize| -> Option { + let Some(node_value) = node_values.get(i) else { + return None; + }; + *node_value + }; + let Some(root_node_value) = get_node_value(0) else { + panic!("require root node value"); + }; + let root = TreeNode::build_node(root_node_value); + let mut nodes = VecDeque::from_iter([Rc::clone(&root)]); + + let mut i = 1; + while let Some(node) = nodes.pop_front() { + let mut node = node.borrow_mut(); + + if let Some(left_node_value) = get_node_value(i) { + let left_node = TreeNode::build_node(left_node_value); + node.left = Some(Rc::clone(&left_node)); + nodes.push_back(left_node); + } + i += 1; + + if let Some(right_node_value) = get_node_value(i) { + let right_node = TreeNode::build_node(right_node_value); + node.right = Some(Rc::clone(&right_node)); + nodes.push_back(right_node); + } + i += 1; + } + + root + } + + fn to_node_values(root: Rc>) -> Vec> { + let mut nodes = VecDeque::from_iter([Some(root)]); + let mut node_values = vec![]; + + while let Some(node) = nodes.pop_front() { + let Some(node) = node else { + node_values.push(None); + continue; + }; + + let node = node.borrow(); + node_values.push(Some(node.val)); + nodes.push_back(node.left.as_ref().map(Rc::clone)); + nodes.push_back(node.right.as_ref().map(Rc::clone)); + } + + while node_values.last().is_some_and(|v| v.is_none()) { + node_values.pop(); + } + + node_values + } + + #[test] + fn step1_split_bst_test_1() { + // BST: [4,2,6,1,3,5,7] + // v=2: <=2 is {2,1}, >2 is {4,3,6,5,7} + let root = to_binary_search_tree(&vec![ + Some(4), + Some(2), + Some(6), + Some(1), + Some(3), + Some(5), + Some(7), + ]); + let picked = Solution::split_b_s_t(root, 2); + assert_eq!(picked.borrow().val, 4); + assert_eq!(picked.borrow().count_nodes(), 5); + + // v=4: <=4 is {4,2,1,3}, >4 is {6,5,7} + let root = to_binary_search_tree(&vec![ + Some(4), + Some(2), + Some(6), + Some(1), + Some(3), + Some(5), + Some(7), + ]); + let picked = Solution::split_b_s_t(root, 4); + assert_eq!(picked.borrow().val, 4); + assert_eq!(picked.borrow().count_nodes(), 4); + } + + #[test] + fn step1_split_bst_test_2() { + // BST: [5,2,7,1,3,6] + // v=4: <=4 is {2,1,3}, >4 is {5,7,6} + let root = + to_binary_search_tree(&vec![Some(5), Some(2), Some(7), Some(1), Some(3), Some(6)]); + let picked = Solution::split_b_s_t(root, 4); + assert_eq!(picked.borrow().val, 5); + assert_eq!(picked.borrow().count_nodes(), 3); + + // BST: [5,2,7,1,3,6] + // v=1: <=1 is {1}, >1 is {5,2,7,#,3,6} + let root = + to_binary_search_tree(&vec![Some(5), Some(2), Some(7), Some(1), Some(3), Some(6)]); + let picked = Solution::split_b_s_t(root, 1); + assert_eq!(picked.borrow().val, 5); + assert_eq!(picked.borrow().count_nodes(), 5); + assert_eq!( + to_node_values(picked), + vec![Some(5), Some(2), Some(7), None, Some(3), Some(6)] + ); + } + + #[test] + fn step1_to_nodes_test() { + let node_values = vec![Some(5), None, Some(7), Some(6)]; + let root = to_binary_search_tree(&node_values); + assert_eq!(to_node_values(root), node_values); + } + + #[test] + fn step1_to_binary_search_tree_test() { + let node_values = vec![Some(5), None, Some(7), Some(6)]; + let actual_root = to_binary_search_tree(&node_values); + + let expect_root = TreeNode::build_node(5); + expect_root.borrow_mut().right = Some(TreeNode::build_node(7)); + expect_root + .borrow_mut() + .right + .as_ref() + .map(Rc::clone) + .unwrap() + .borrow_mut() + .left = Some(TreeNode::build_node(6)); + + assert_eq!(actual_root, expect_root); + } + + #[test] + fn step1_count_nodes_test() { + let node_values = vec![Some(5), None, Some(7), Some(6)]; + let root = to_binary_search_tree(&node_values); + assert_eq!(root.borrow().count_nodes(), 3); + + let node_values = vec![Some(5), None, Some(7)]; + let root = to_binary_search_tree(&node_values); + assert_eq!(root.borrow().count_nodes(), 2); + + let node_values = vec![Some(5)]; + let root = to_binary_search_tree(&node_values); + assert_eq!(root.borrow().count_nodes(), 1); + } +} diff --git a/src/bin/step1a.rs b/src/bin/step1a.rs new file mode 100644 index 0000000..08c9684 --- /dev/null +++ b/src/bin/step1a.rs @@ -0,0 +1,292 @@ +// step1a +// 目的: 別の実装方法(再帰->ループ)で練習する。 + +/* + 問題の理解 + - 二分探索木の根であるrootと整数vが与えられる。 + あるノードから見た時に左側のサブツリーにはノード自身が持つ値より小さい値を持つノードで構成される + あるノードから見た時に右側のサブツリーにはノード自身が持つ値より大きい値を持つノードで構成される + 整数v以下のノードで構成されるツリーと整数vを超えるノードで構成されるツリーに分割する。 + 分割したサブツリーうちノード数が多い方のサブツリーを返す。サブツリーの数が同じ場合はrootノードの値が大きい方のサブツリーを返す。 + + step1からの変更点 + - count_nodesの再帰処理をループへ変更 + - split_treeの再帰処理をループへ変更 + - ループへの書き直しを行ったが、直列のになるような木構造を扱えないロジックが出来上がったので、GPT-5.2に聞きつつ修正した。 + dummy,tailポインタで操作対象のノードのポインタを管理する修正を行った。 + + 所感 + - split_b_s_tでノードの数が多いサブツリー(等しいときは根のノードの値が大きい方)を返しているが、比較の仕様をOrdトレイトといして実装して、TreeNode自体で比較できるようにするのも良さそう。 + ツリーを構成するノードの数が多い(等しいときはツリーの根の値が大きい)方を大きいサブツリーとするというドメイン知識をTreeNodeにカプセル化できるという感覚。 +*/ + +use std::{cell::RefCell, collections::VecDeque, rc::Rc}; + +#[derive(PartialEq, Debug)] +pub struct TreeNode { + val: u32, + left: Option>>, + right: Option>>, +} +impl TreeNode { + pub fn build_node(val: u32) -> Rc> { + Rc::new(RefCell::new(TreeNode::new(val))) + } + + pub fn count_nodes(&self) -> usize { + let mut node_counts = 1; + let mut frontiers = VecDeque::from_iter([ + self.left.as_ref().map(Rc::clone), + self.right.as_ref().map(Rc::clone), + ]); + + while let Some(node) = frontiers.pop_front() { + let Some(node) = node else { + continue; + }; + let node = node.borrow(); + + node_counts += 1; + frontiers.push_back(node.left.as_ref().map(Rc::clone)); + frontiers.push_back(node.right.as_ref().map(Rc::clone)); + } + + node_counts + } + + fn new(val: u32) -> Self { + Self { + val, + right: None, + left: None, + } + } +} + +pub struct Solution {} +impl Solution { + pub fn split_b_s_t(root: Rc>, v: u32) -> Rc> { + let (left_subtree, right_subtree) = Self::split_tree(root, v); + let (left_subtree, right_subtree) = match (left_subtree, right_subtree) { + (Some(l), None) => return l, + (None, Some(r)) => return r, + (Some(l), Some(r)) => (l, r), + (None, None) => unreachable!(), + }; + + let (left_node_count, right_node_count) = ( + left_subtree.borrow().count_nodes(), + right_subtree.borrow().count_nodes(), + ); + if left_node_count < right_node_count { + return right_subtree; + } else if right_node_count < left_node_count { + return left_subtree; + }; + + if left_subtree.borrow().val < right_subtree.borrow().val { + return right_subtree; + } + + left_subtree + } + + fn split_tree( + root: Rc>, + v: u32, + ) -> (Option>>, Option>>) { + let dummy_left_root = TreeNode::build_node(0); + let dummy_right_root = TreeNode::build_node(0); + let mut left_subtree_tail = Rc::clone(&dummy_left_root); + let mut right_subtree_tail = Rc::clone(&dummy_right_root); + let mut current_node_cursor = Some(root); + + while let Some(node) = current_node_cursor.as_ref().map(Rc::clone) { + let node_val = node.borrow().val; + + if node_val <= v { + let next_node_cursor = node.borrow_mut().right.take(); + + left_subtree_tail.borrow_mut().right = Some(Rc::clone(&node)); + left_subtree_tail = node; + + current_node_cursor = next_node_cursor; + } else { + let next_cursor = node.borrow_mut().left.take(); + + right_subtree_tail.borrow_mut().left = Some(Rc::clone(&node)); + right_subtree_tail = node; + + current_node_cursor = next_cursor; + } + } + + let (left_subtree, right_subtree) = ( + dummy_left_root.borrow().right.as_ref().map(Rc::clone), + dummy_right_root.borrow().left.as_ref().map(Rc::clone), + ); + + (left_subtree, right_subtree) + } +} + +#[cfg(test)] +mod tests { + use std::collections::VecDeque; + + use super::*; + + fn to_binary_search_tree(node_values: &Vec>) -> Rc> { + let get_node_value = |i: usize| -> Option { + let Some(node_value) = node_values.get(i) else { + return None; + }; + *node_value + }; + let Some(root_node_value) = get_node_value(0) else { + panic!("require root node value"); + }; + let root = TreeNode::build_node(root_node_value); + let mut nodes = VecDeque::from_iter([Rc::clone(&root)]); + + let mut i = 1; + while let Some(node) = nodes.pop_front() { + let mut node = node.borrow_mut(); + + if let Some(left_node_value) = get_node_value(i) { + let left_node = TreeNode::build_node(left_node_value); + node.left = Some(Rc::clone(&left_node)); + nodes.push_back(left_node); + } + i += 1; + + if let Some(right_node_value) = get_node_value(i) { + let right_node = TreeNode::build_node(right_node_value); + node.right = Some(Rc::clone(&right_node)); + nodes.push_back(right_node); + } + i += 1; + } + + root + } + + fn to_node_values(root: Rc>) -> Vec> { + let mut nodes = VecDeque::from_iter([Some(root)]); + let mut node_values = vec![]; + + while let Some(node) = nodes.pop_front() { + let Some(node) = node else { + node_values.push(None); + continue; + }; + + let node = node.borrow(); + node_values.push(Some(node.val)); + nodes.push_back(node.left.as_ref().map(Rc::clone)); + nodes.push_back(node.right.as_ref().map(Rc::clone)); + } + + while node_values.last().is_some_and(|v| v.is_none()) { + node_values.pop(); + } + + node_values + } + + #[test] + fn step1a_split_bst_test_1() { + // BST: [4,2,6,1,3,5,7] + // v=2: <=2 is {2,1}, >2 is {4,3,6,5,7} + let root = to_binary_search_tree(&vec![ + Some(4), + Some(2), + Some(6), + Some(1), + Some(3), + Some(5), + Some(7), + ]); + let picked = Solution::split_b_s_t(root, 2); + assert_eq!(picked.borrow().val, 4); + assert_eq!(picked.borrow().count_nodes(), 5); + + // v=4: <=4 is {4,2,1,3}, >4 is {6,5,7} + let root = to_binary_search_tree(&vec![ + Some(4), + Some(2), + Some(6), + Some(1), + Some(3), + Some(5), + Some(7), + ]); + let picked = Solution::split_b_s_t(root, 4); + assert_eq!(picked.borrow().val, 4); + assert_eq!(picked.borrow().count_nodes(), 4); + } + + #[test] + fn step1a_split_bst_test_2() { + // BST: [5,2,7,1,3,6] + // v=4: <=4 is {2,1,3}, >4 is {5,7,6} + let root = + to_binary_search_tree(&vec![Some(5), Some(2), Some(7), Some(1), Some(3), Some(6)]); + let picked = Solution::split_b_s_t(root, 4); + assert_eq!(picked.borrow().val, 5); + assert_eq!(picked.borrow().count_nodes(), 3); + + // BST: [5,2,7,1,3,6] + // v=1: <=1 is {1}, >1 is {5,2,7,#,3,6} + let root = + to_binary_search_tree(&vec![Some(5), Some(2), Some(7), Some(1), Some(3), Some(6)]); + let picked = Solution::split_b_s_t(root, 1); + assert_eq!(picked.borrow().val, 5); + assert_eq!(picked.borrow().count_nodes(), 5); + assert_eq!( + to_node_values(picked), + vec![Some(5), Some(2), Some(7), None, Some(3), Some(6)] + ); + } + + #[test] + fn step1a_to_nodes_test() { + let node_values = vec![Some(5), None, Some(7), Some(6)]; + let root = to_binary_search_tree(&node_values); + assert_eq!(to_node_values(root), node_values); + } + + #[test] + fn step1a_to_binary_search_tree_test() { + let node_values = vec![Some(5), None, Some(7), Some(6)]; + let actual_root = to_binary_search_tree(&node_values); + + let expect_root = TreeNode::build_node(5); + expect_root.borrow_mut().right = Some(TreeNode::build_node(7)); + expect_root + .borrow_mut() + .right + .as_ref() + .map(Rc::clone) + .unwrap() + .borrow_mut() + .left = Some(TreeNode::build_node(6)); + + assert_eq!(actual_root, expect_root); + } + + #[test] + fn step1a_count_nodes_test() { + let node_values = vec![Some(5), None, Some(7), Some(6)]; + let root = to_binary_search_tree(&node_values); + assert_eq!(root.borrow().count_nodes(), 3); + + let node_values = vec![Some(5), None, Some(7)]; + let root = to_binary_search_tree(&node_values); + assert_eq!(root.borrow().count_nodes(), 2); + + let node_values = vec![Some(5)]; + let root = to_binary_search_tree(&node_values); + assert_eq!(root.borrow().count_nodes(), 1); + } +} diff --git a/src/bin/step2.rs b/src/bin/step2.rs new file mode 100644 index 0000000..1ae4ad6 --- /dev/null +++ b/src/bin/step2.rs @@ -0,0 +1,300 @@ +// Step2 +// 目的: 自然な書き方を考えて整理する + +// 方法 +// Step1のコードを読みやすくしてみる +// 他の人のコードを2つは読んでみること +// 正解したら終わり + +// 以下をメモに残すこと +// 講師陣はどのようなコメントを残すだろうか? +// 他の人のコードを読んで考えたこと +// 改善する時に考えたこと + +/* + コメント集、他の人のコードを読んで考えたこと + https://github.com/goto-untrapped/Arai60/pull/54#discussion_r1759975142 + > left, rightよりsmaller, largerの分かりやすいかと思いました。 + - なるほど。vよりも小さい値を持つノードで構成されるサブツリー、大きい値を持つノードで構成されるサブツリーに分けるので確かにそうだなと思った。 + 二分探索木において、左は小さい、右は大きいという前提があるので自分はleft,rightにしているのだなと思った。 + + https://github.com/Yoshiki-Iwasa/Arai60/pull/41/changes#r1710591176 + - 型エイリアスの使い方や、そもそも型とはどのような使い方をするものなのかといったやりとりがされていて勉強になる。 + ここの議論と少しずれるが自分はRc>型のインスタンスを生成するときに毎回書くのが面倒なので、ヘルパーメソッドとしてbuild_nodeを実装した。 + type Tree = Rc>; としてシグネチャで利用しても良いかと思ったが、TreeよりはTreeNodeの方が意味が近く型エイリアスにすることで意味がおかしくなりそうだったので止めた。 + この点についてよりよい方法がありそうなのでGPT-5.2に聞いてみたところ、参照であることを示す 型名+Refといった型エイリアス命名パターンがよく用いられているとのことだった。 + 今回の例では type TreeNodeRef = Rc>; 又は type TreeNodeHandle = Rc> とするのがRustの文化的に一般的そうだった。 + reqwestクレートでは参照でラップされる側の型名にRefとつけていた。おそらくnewtypeパターンと呼ばれるもの。(reqwestクレートのソースコードを見たときの記憶が少し残っていて思い出した。) + https://docs.rs/reqwest/latest/src/reqwest/async_impl/client.rs.html#94 + + 改善する時に考えたこと + - 変数命名について left,right -> smaller,larger にする。小さいまとまりと大きいまとまりに分けているためこっちのほうが意味が近いと思った。 + - 型エイリアスを活用する + - TreeNode同士の比較をOrdトレイトを実装して、シンプルに比較できるようにする。 + + 所感 + - すっきりと書けた気はするものの、Ordトレイトの実装内で毎回O(n)となるようなノードの数え上げを暗黙的に行っているのが気になった。 + 比較演算子による比較(Ord impl)という低いレベルの操作でノードの数え上げ処理を暗黙的に呼び出しており、利用者側が意図せずコストの高い処理を呼び出してしまうという見方もできる。 + ただ、ノードの個数をTreeNodeのフィールドとして持つことでキャッシュすれば良いかというとそうでもなくて、ノードの追加・削除時に必ずノード個数(キャッシュ)の更新を行う必要がある。 + この場合、ノード追加・削除処理をTreeNodeが公開するのAPI経由でしか行えないように実装しないと、キャッシュしたノード個数が不正な値になりえるのでやっかいなバグになりそう。 + TreeNodeのインスタンス同士の比較条件をOrd実装で表現することによって、「ツリーを構成するノードの個数による比較をする。等しい場合は根の値で比較する。」というドメイン知識をカプセル化できているのは良い点だと思った。 +*/ + +use std::{cell::RefCell, cmp::Ordering, collections::VecDeque, rc::Rc}; + +#[derive(PartialEq, Eq, Debug)] +pub struct TreeNode { + val: u32, + left: Option, + right: Option, +} +impl TreeNode { + pub fn build_node(val: u32) -> TreeNodeRef { + Rc::new(RefCell::new(TreeNode::new(val))) + } + + fn count_nodes(&self) -> usize { + let mut nodes_count = 1; + let mut nodes = VecDeque::from_iter([ + self.left.as_ref().map(Rc::clone), + self.right.as_ref().map(Rc::clone), + ]); + + while let Some(node) = nodes.pop_front() { + let Some(node) = node else { + continue; + }; + + nodes_count += 1; + nodes.push_back(node.borrow().left.as_ref().map(Rc::clone)); + nodes.push_back(node.borrow().right.as_ref().map(Rc::clone)); + } + + nodes_count + } + + fn new(val: u32) -> Self { + Self { + val, + right: None, + left: None, + } + } +} +impl Ord for TreeNode { + fn cmp(&self, other: &Self) -> Ordering { + self.count_nodes() + .cmp(&other.count_nodes()) + .then(self.val.cmp(&other.val)) + } +} +impl PartialOrd for TreeNode { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +pub type TreeNodeRef = Rc>; + +pub struct Solution {} +impl Solution { + pub fn split_b_s_t(root: TreeNodeRef, v: u32) -> TreeNodeRef { + let (smaller_root, larger_root) = match Self::split_tree(Some(root), v) { + (Some(smaller_root), None) => return smaller_root, + (None, Some(larger_root)) => return larger_root, + (Some(smaller_root), Some(larger_root)) => (smaller_root, larger_root), + _ => unreachable!(), + }; + + if smaller_root < larger_root { + return larger_root; + }; + smaller_root + } + + fn split_tree(node: Option, v: u32) -> (Option, Option) { + match node { + None => (None, None), + Some(node) => { + let node_val = node.borrow().val; + + if node_val <= v { + let right_node = node.borrow_mut().right.take(); + + let (smaller_root, larger_root) = Self::split_tree(right_node, v); + node.borrow_mut().right = smaller_root; + + (Some(node), larger_root) + } else { + let left_node = node.borrow_mut().left.take(); + + let (smaller_root, larger_root) = Self::split_tree(left_node, v); + node.borrow_mut().left = larger_root; + + (smaller_root, Some(node)) + } + } + } + } +} + +#[cfg(test)] +mod tests { + use std::collections::VecDeque; + + use super::*; + + fn to_binary_search_tree(node_values: &Vec>) -> TreeNodeRef { + let get_node_value = |i: usize| -> Option { + let Some(node_value) = node_values.get(i) else { + return None; + }; + *node_value + }; + let Some(root_node_value) = get_node_value(0) else { + panic!("require root node value"); + }; + let root = TreeNode::build_node(root_node_value); + let mut nodes = VecDeque::from_iter([Rc::clone(&root)]); + + let mut i = 1; + while let Some(node) = nodes.pop_front() { + let mut node = node.borrow_mut(); + + if let Some(left_node_value) = get_node_value(i) { + let left_node = TreeNode::build_node(left_node_value); + node.left = Some(Rc::clone(&left_node)); + nodes.push_back(left_node); + } + i += 1; + + if let Some(right_node_value) = get_node_value(i) { + let right_node = TreeNode::build_node(right_node_value); + node.right = Some(Rc::clone(&right_node)); + nodes.push_back(right_node); + } + i += 1; + } + + root + } + + fn to_node_values(root: Rc>) -> Vec> { + let mut nodes = VecDeque::from_iter([Some(root)]); + let mut node_values = vec![]; + + while let Some(node) = nodes.pop_front() { + let Some(node) = node else { + node_values.push(None); + continue; + }; + + let node = node.borrow(); + node_values.push(Some(node.val)); + nodes.push_back(node.left.as_ref().map(Rc::clone)); + nodes.push_back(node.right.as_ref().map(Rc::clone)); + } + + while node_values.last().is_some_and(|v| v.is_none()) { + node_values.pop(); + } + + node_values + } + + #[test] + fn step2_split_bst_test_1() { + // BST: [4,2,6,1,3,5,7] + // v=2: <=2 is {2,1}, >2 is {4,3,6,5,7} + let root = to_binary_search_tree(&vec![ + Some(4), + Some(2), + Some(6), + Some(1), + Some(3), + Some(5), + Some(7), + ]); + let picked = Solution::split_b_s_t(root, 2); + assert_eq!(picked.borrow().val, 4); + assert_eq!(picked.borrow().count_nodes(), 5); + + // v=4: <=4 is {4,2,1,3}, >4 is {6,5,7} + let root = to_binary_search_tree(&vec![ + Some(4), + Some(2), + Some(6), + Some(1), + Some(3), + Some(5), + Some(7), + ]); + let picked = Solution::split_b_s_t(root, 4); + assert_eq!(picked.borrow().val, 4); + assert_eq!(picked.borrow().count_nodes(), 4); + } + + #[test] + fn step2_split_bst_test_2() { + // BST: [5,2,7,1,3,6] + // v=4: <=4 is {2,1,3}, >4 is {5,7,6} + let root = + to_binary_search_tree(&vec![Some(5), Some(2), Some(7), Some(1), Some(3), Some(6)]); + let picked = Solution::split_b_s_t(root, 4); + assert_eq!(picked.borrow().val, 5); + assert_eq!(picked.borrow().count_nodes(), 3); + + // BST: [5,2,7,1,3,6] + // v=1: <=1 is {1}, >1 is {5,2,7,#,3,6} + let root = + to_binary_search_tree(&vec![Some(5), Some(2), Some(7), Some(1), Some(3), Some(6)]); + let picked = Solution::split_b_s_t(root, 1); + assert_eq!(picked.borrow().val, 5); + assert_eq!(picked.borrow().count_nodes(), 5); + assert_eq!( + to_node_values(picked), + vec![Some(5), Some(2), Some(7), None, Some(3), Some(6)] + ); + } + + #[test] + fn step2_to_nodes_test() { + let node_values = vec![Some(5), None, Some(7), Some(6)]; + let root = to_binary_search_tree(&node_values); + assert_eq!(to_node_values(root), node_values); + } + + #[test] + fn step2_to_binary_search_tree_test() { + let node_values = vec![Some(5), None, Some(7), Some(6)]; + let actual_root = to_binary_search_tree(&node_values); + + let expect_root = TreeNode::build_node(5); + expect_root.borrow_mut().right = Some(TreeNode::build_node(7)); + expect_root + .borrow_mut() + .right + .as_ref() + .map(Rc::clone) + .unwrap() + .borrow_mut() + .left = Some(TreeNode::build_node(6)); + + assert_eq!(actual_root, expect_root); + } + + #[test] + fn step2_count_nodes_test() { + let node_values = vec![Some(5), None, Some(7), Some(6)]; + let root = to_binary_search_tree(&node_values); + assert_eq!(root.borrow().count_nodes(), 3); + + let node_values = vec![Some(5), None, Some(7)]; + let root = to_binary_search_tree(&node_values); + assert_eq!(root.borrow().count_nodes(), 2); + + let node_values = vec![Some(5)]; + let root = to_binary_search_tree(&node_values); + assert_eq!(root.borrow().count_nodes(), 1); + } +} diff --git a/src/bin/step3.rs b/src/bin/step3.rs new file mode 100644 index 0000000..760b255 --- /dev/null +++ b/src/bin/step3.rs @@ -0,0 +1,294 @@ +// Step3 +// 目的: 覚えられないのは、なんか素直じゃないはずなので、そこを探し、ゴールに到達する + +// 方法 +// 時間を測りながらもう一度解く +// 10分以内に一度もエラーを吐かず正解 +// これを3回連続でできたら終わり +// レビューを受ける +// 作れないデータ構造があった場合は別途自作すること + +/* + n = nodes.len() + 時間計算量: O(n) + 空間計算量: O(n) +*/ + +/* + 構造体の定義は除き、メソッドの中身は実装したときの時間 + 1回目: 10分15秒 + 2回目: 11分3秒 + 3回目: 8分14秒 +*/ + +/* + 所感 + - ノードの数え上げ処理(count_nodes)でVecDequeを使う必要はないことに気付いたのでVecにした。 +*/ + +use std::{cell::RefCell, cmp::Ordering, rc::Rc}; + +#[derive(PartialEq, Eq, Debug)] +pub struct TreeNode { + val: u32, + left: Option, + right: Option, +} +impl TreeNode { + pub fn build_node(val: u32) -> TreeNodeRef { + Rc::new(RefCell::new(TreeNode::new(val))) + } + + fn count_nodes(&self) -> usize { + let mut nodes_count = 1; + let mut nodes = Vec::from_iter([ + self.left.as_ref().map(Rc::clone), + self.right.as_ref().map(Rc::clone), + ]); + + while let Some(node) = nodes.pop() { + let Some(node) = node else { + continue; + }; + + nodes_count += 1; + nodes.push(node.borrow().left.as_ref().map(Rc::clone)); + nodes.push(node.borrow().right.as_ref().map(Rc::clone)); + } + + nodes_count + } + + fn new(val: u32) -> Self { + Self { + val, + right: None, + left: None, + } + } +} + +impl Ord for TreeNode { + fn cmp(&self, other: &Self) -> Ordering { + self.count_nodes() + .cmp(&other.count_nodes()) + .then(self.val.cmp(&other.val)) + } +} + +impl PartialOrd for TreeNode { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +type TreeNodeRef = Rc>; + +pub struct Solution {} +impl Solution { + pub fn split_binary_search_tree(root: TreeNodeRef, v: u32) -> TreeNodeRef { + let (smaller_root, larger_root) = match Self::split_binary_search_tree_helper(Some(root), v) + { + (Some(smaller_root), None) => return smaller_root, + (None, Some(larger_root)) => return larger_root, + (Some(smaller_root), Some(larger_root)) => (smaller_root, larger_root), + (None, None) => unreachable!(), + }; + + if smaller_root < larger_root { + return larger_root; + } + smaller_root + } + + fn split_binary_search_tree_helper( + node: Option, + v: u32, + ) -> (Option, Option) { + match node { + None => (None, None), + Some(node) => { + let node_val = node.borrow().val; + + if node_val <= v { + let right_node = node.borrow_mut().right.take(); + let (smaller_root, larger_root) = + Self::split_binary_search_tree_helper(right_node, v); + + node.borrow_mut().right = smaller_root; + + (Some(node), larger_root) + } else { + let left_node = node.borrow_mut().left.take(); + let (smaller_root, larger_root) = + Self::split_binary_search_tree_helper(left_node, v); + + node.borrow_mut().left = larger_root; + + (smaller_root, Some(node)) + } + } + } + } +} + +#[cfg(test)] +mod tests { + use std::collections::VecDeque; + + use super::*; + + fn to_binary_search_tree(node_values: &Vec>) -> TreeNodeRef { + let get_node_value = |i: usize| -> Option { + let Some(node_value) = node_values.get(i) else { + return None; + }; + *node_value + }; + let Some(root_node_value) = get_node_value(0) else { + panic!("require root node value"); + }; + let root = TreeNode::build_node(root_node_value); + let mut nodes = VecDeque::from_iter([Rc::clone(&root)]); + + let mut i = 1; + while let Some(node) = nodes.pop_front() { + let mut node = node.borrow_mut(); + + if let Some(left_node_value) = get_node_value(i) { + let left_node = TreeNode::build_node(left_node_value); + node.left = Some(Rc::clone(&left_node)); + nodes.push_back(left_node); + } + i += 1; + + if let Some(right_node_value) = get_node_value(i) { + let right_node = TreeNode::build_node(right_node_value); + node.right = Some(Rc::clone(&right_node)); + nodes.push_back(right_node); + } + i += 1; + } + + root + } + + fn to_node_values(root: Rc>) -> Vec> { + let mut nodes = VecDeque::from_iter([Some(root)]); + let mut node_values = vec![]; + + while let Some(node) = nodes.pop_front() { + let Some(node) = node else { + node_values.push(None); + continue; + }; + + let node = node.borrow(); + node_values.push(Some(node.val)); + nodes.push_back(node.left.as_ref().map(Rc::clone)); + nodes.push_back(node.right.as_ref().map(Rc::clone)); + } + + while node_values.last().is_some_and(|v| v.is_none()) { + node_values.pop(); + } + + node_values + } + + #[test] + fn step3_split_bst_test_1() { + // BST: [4,2,6,1,3,5,7] + // v=2: <=2 is {2,1}, >2 is {4,3,6,5,7} + let root = to_binary_search_tree(&vec![ + Some(4), + Some(2), + Some(6), + Some(1), + Some(3), + Some(5), + Some(7), + ]); + let picked = Solution::split_binary_search_tree(root, 2); + assert_eq!(picked.borrow().val, 4); + assert_eq!(picked.borrow().count_nodes(), 5); + + // v=4: <=4 is {4,2,1,3}, >4 is {6,5,7} + let root = to_binary_search_tree(&vec![ + Some(4), + Some(2), + Some(6), + Some(1), + Some(3), + Some(5), + Some(7), + ]); + let picked = Solution::split_binary_search_tree(root, 4); + assert_eq!(picked.borrow().val, 4); + assert_eq!(picked.borrow().count_nodes(), 4); + } + + #[test] + fn step3_split_bst_test_2() { + // BST: [5,2,7,1,3,6] + // v=4: <=4 is {2,1,3}, >4 is {5,7,6} + let root = + to_binary_search_tree(&vec![Some(5), Some(2), Some(7), Some(1), Some(3), Some(6)]); + let picked = Solution::split_binary_search_tree(root, 4); + assert_eq!(picked.borrow().val, 5); + assert_eq!(picked.borrow().count_nodes(), 3); + + // BST: [5,2,7,1,3,6] + // v=1: <=1 is {1}, >1 is {5,2,7,#,3,6} + let root = + to_binary_search_tree(&vec![Some(5), Some(2), Some(7), Some(1), Some(3), Some(6)]); + let picked = Solution::split_binary_search_tree(root, 1); + assert_eq!(picked.borrow().val, 5); + assert_eq!(picked.borrow().count_nodes(), 5); + assert_eq!( + to_node_values(picked), + vec![Some(5), Some(2), Some(7), None, Some(3), Some(6)] + ); + } + + #[test] + fn step3_to_nodes_test() { + let node_values = vec![Some(5), None, Some(7), Some(6)]; + let root = to_binary_search_tree(&node_values); + assert_eq!(to_node_values(root), node_values); + } + + #[test] + fn step3_to_binary_search_tree_test() { + let node_values = vec![Some(5), None, Some(7), Some(6)]; + let actual_root = to_binary_search_tree(&node_values); + + let expect_root = TreeNode::build_node(5); + expect_root.borrow_mut().right = Some(TreeNode::build_node(7)); + expect_root + .borrow_mut() + .right + .as_ref() + .map(Rc::clone) + .unwrap() + .borrow_mut() + .left = Some(TreeNode::build_node(6)); + + assert_eq!(actual_root, expect_root); + } + + #[test] + fn step3_count_nodes_test() { + let node_values = vec![Some(5), None, Some(7), Some(6)]; + let root = to_binary_search_tree(&node_values); + assert_eq!(root.borrow().count_nodes(), 3); + + let node_values = vec![Some(5), None, Some(7)]; + let root = to_binary_search_tree(&node_values); + assert_eq!(root.borrow().count_nodes(), 2); + + let node_values = vec![Some(5)]; + let root = to_binary_search_tree(&node_values); + assert_eq!(root.borrow().count_nodes(), 1); + } +}