問題
二分探索木のroot と、val をval を
- 二分探索木では、
どの 節でも、 左の 部分木の 値は すべて その 節より 小さく、 右の 部分木の 値は すべて その 節より 大きくなっています - 足し方は 1 つに
決めます。 根から、 valが節より 小さければ 左、 大きければ 右へ 進み、 子の 無い所に 出たら、 そこへ 新しい 節を 葉としてつなぎます。 木の 形を 組み替えてはいけません - 各節は
val、left、rightを持ちます。 Go の 節は TreeNodeで、Val、Left、Rightです。新しい 節は、 Python では TreeNode(val)、JavaScript では new TreeNode(val)で作れます。 Go では TreeNodeを作り、 その アドレスを 使います (解答の 初めの 数行を 見てください) rootが空の 木の こともあります。 その ときは、 valの節 1 つだけの 木を返します - 節の
数は 0 以上 500 以下です。 値は どれも 違い、 valも含めて -100000000 以上 100000000 以下です
例では、null で、null は
入力と出力の例
例 1
50 は 40 より
入力
root = [40, 20, 60, 10, 30]
val = 50出力
[40, 20, 60, 10, 30, 50]例 2
同じ木に 35 を
入力
root = [40, 20, 60, 10, 30]
val = 35出力
[40, 20, 60, 10, 30, null, null,
null, null, null, 35]例 3
空の
入力
root = []
val = 3出力
[3]面接での聞かれ方
面接では、
- 「二分探索木に
値を 1 つ足して、 根を 返してください」 - 「足し方は
何通りも ありますが、 いちばん素直な 形でかまいません」と 言われ、 葉として 足す形を 選べるかを 見られます - 書き終えた
あとに 「再帰でも書けますか?」 「同じ値を 何度も 足すと、 木は どうなりますか?」と 聞かれます
木の
アルゴリズムのチートシートの「再帰と木」に、この型の要点を表とコードでまとめています。
まず 考える手順
段 1
まず、val がval は
段 2
行き当たったval をval は
段 3
空きにつなぐには、val と
段 4
返すのは
解答
Python
Python
def insert_bst(root, val):
leaf = TreeNode(val)
if root is None:
return leaf
parent = root
node = root
while node:
parent = node
if val < node.val:
node = node.left
else:
node = node.right
if val < parent.val:
parent.left = leaf
else:
parent.right = leaf
return rootJavaScript
JavaScript
function insertBst(root, val) {
const leaf =
new TreeNode(val);
if (root === null) {
return leaf;
}
let parent = root;
let node = root;
while (node !== null) {
parent = node;
node = val < node.val
? node.left
: node.right;
}
if (val < parent.val) {
parent.left = leaf;
} else {
parent.right = leaf;
}
return root;
}Go
Go
func insertBst(
root *TreeNode, val int,
) *TreeNode {
leaf := &TreeNode{Val: val}
if root == nil {
return leaf
}
parent := root
node := root
for node != nil {
parent = node
if val < node.Val {
node = node.Left
} else {
node = node.Right
}
}
if val < parent.Val {
parent.Left = leaf
} else {
parent.Right = leaf
}
return root
}parent は、node がnode はparent を
計算量
- 時間は O(h) です。
h は 木の 高さです。 根から 葉まで 1 本道を 下るだけです。 木が 片側に 伸びきると h は n に なり、 O(n) です - 使う
記憶は O(1) です。 新しい 節 1 つと、 parentとnodeの 2 つの置き場だけを 使い、 再帰の 呼び出しも 積みません
よく ある間違い
- 空の
木を 見落とす。 rootが空なのに 親を たどり 始めると、 空の 節の valを読んで 止まります。 最初に、 新しい 節を そのまま返します - 空きに
出た あとで、 つなぐ先を失う。 nodeを空に なるまで 進めると、 つな ぐべき親が もう 手元に ありません。 進む前に 親を 覚えておくか、 子が 空かを 1 つ 手前で 確かめます - 根に
近い所へ 割り込ませる。 値の 大小だけを 見て 途中の 節の 間に 差し込むと、 その下の 部分木との 大小が 崩れます。 葉として 足せば、 どの 比べ方も 変わりません - 左右の
向きを 逆に比べる。 val < node.valで右へ 進むと、 決まりと 逆の 側に 付きます。 足した あとの 木を 中順に 読み、 小さい 順に なっているかで 確かめられます - 再帰で
書いて 戻り値を 入れ直さない。 再帰で 書く ときは 「足した あとの 部分木の 根」を 返し、 root.leftやroot.rightに入れ直します。 入れ直さないと、 作った 節が どこに もつながりません
解答を動かした版 Python 3.12.14Node.js 22.23.4Go 1.24.6確認日 2026年10月30日
面接での 話し方の例
書き始める
「値を
探すときと 同じに、 小さければ 左、 大きければ 右へ 進みます。 valは木に 無いので、 必ず子の 無い所に 出ます。 そこへ 葉としてつな げば、 ほかの 節は 1 つも 動か さずに 決まりを 保てます。 つな ぐために 親を 覚えながら 下ります。 木が 空なら、 新しい 節を そのまま 根として 返します。 時間は 木の 高さ分の O(h)、 記憶は O(1) です。」
書き終えたら、
「例 2 で
たどります。 35 は 40 より 小さいので 左の 20 へ、 20 より 大きいので 右の 30 へ 進みます。 30 より 大きいので 右へ 進むと 空なので、 ここで 止まります。 親の 30 より 大きいので、 30 の 右の 子として 35 を つなぎ、 根の 40 を 返します。」
