Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 110 additions & 0 deletions 776/776.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
一応ここに書いたコードはすべてLLMに聞いて期待通りに動作するだろうとは言われたコードですが、LeetCodeなどで試せているわけではないのでもしかしたら動かないかもしれないです。動かないと思ったら教えてください。

## 何も見ずに解いてみる

```cpp
class Solution {
public:
vector<TreeNode*> splitBST(TreeNode* root, int target) {
if (root == nullptr) {
return {nullptr, nullptr};
}
if (root->val <= target) {
vector<TreeNode*> right_split = splitBST(root->right, target);
TreeNode* lesser_root_of_right = right_split[0];
TreeNode* greater_root_of_right = right_split[1];
root->right = lesser_root_of_right;
return {root, greater_root_of_right};
}
else {
vector<TreeNode*> left_split = splitBST(root->left, target);
TreeNode* lesser_root_of_left = left_split[0];
TreeNode* greater_root_of_left = left_split[1];
root->left = greater_root_of_left;
return {lesser_root_of_left, root};
}
}
};
```

## 他の人のコードを見てみる

https://github.com/Ryotaro25/leetcode_first60/pull/50/files
https://github.com/Mike0121/LeetCode/pull/16/files
https://github.com/tokuhirat/LeetCode/pull/47/files

最初見たときループ版が何をやっているのかあまりわからなかったがしばらく考えているとなんとなく分かった。
ループ版も書いてみる。

```cpp
class Solution {
public:
vector<TreeNode*> splitBST(TreeNode* root, int target) {
TreeNode* lesser_root = nullptr;
TreeNode* greater_root = nullptr;
TreeNode** lesser_subtree_root_to_fill = &lesser_root;
TreeNode** greater_subtree_root_to_fill = &greater_root;
TreeNode* node = root;
while (node) {
if (node->val <= target) {
*lesser_subtree_root_to_fill = node;
TreeNode* tmp = node->right;
node->right = nullptr;
lesser_subtree_root_to_fill = &node->right;
node = tmp;
}
else {
*greater_subtree_root_to_fill = node;
TreeNode* tmp = node->left;
node->left = nullptr;
greater_subtree_root_to_fill = &node->left;
node = tmp;
}
}
return {lesser_root, greater_root};
}
};
```

変数名の組み合わせはsmaller, greaterとすると対称的過ぎてx < target, x > targetみたいな印象になる気がする(x <= target, x > targetではなく)
ただ別にlesserでもその印象はそんなに変わらないかも・・・

再帰でやると全部のノードについて関数を呼び出さなきゃいけないので時間計算量がO(N)になるが、ループだと必要なポインタだけ変えていくので階層分で済んで(バランスされた木なら)O(logN)になる。
(再帰でも空間計算量はO(logN)かな?)

あと、番兵をnewで作るときは関数を終わるときにdeleteしないとメモリーリークになってしまうっぽい。
ただ、`TreeNode lesser_bst_node()`みたいな感じで作ればスコープを抜けたときに自動で解放されるらしい。

関数の返り値は本当はstd::pairとかにしたい気がする。

## 最終コード

```cpp
class Solution {
public:
vector<TreeNode*> splitBST(TreeNode* root, int target) {
TreeNode* lesser_root = nullptr;
TreeNode* greater_root = nullptr;
TreeNode** lesser_subtree_root_to_find = &lesser_root;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lesser_insert_position など node そのものではないことが変数名からわかると、L96 の操作の意味が読みやすいと思いました。

TreeNode** greater_subtree_root_to_find = &greater_root;
TreeNode* node = root;
while (node) {
if (node->val <= target) {
*lesser_subtree_root_to_find = node;
TreeNode* tmp = node->right;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tmp は意味がある変数なので、next_node_to_split ぐらいでも良いかなと思いました。

node->right = nullptr;
lesser_subtree_root_to_find = &node->right;
node = tmp;
}
else {
*greater_subtree_root_to_find = node;
TreeNode* tmp = node->left;
node->left = nullptr;
greater_subtree_root_to_find = &node->left;
node = tmp;
}
}
return {lesser_root, greater_root};
}
};
```