問題
二分探索木のroot と、k をk 番目 (1 から
- 二分探索木では、
どの 節でも、 左の 部分木の 値は すべて その 節より 小さく、 右の 部分木の 値は すべて その 節より 大きくなっています - 各節は
val、left、rightを持ちます。 Go の 節は TreeNodeで、Val、Left、Rightです - 節の
数を n と すると、 n は 1 以上 500 以下、 kは 1 以上 n 以下です。値は どれも 違い、 -10000 以上 10000 以下です - 木を
再帰で たどらず、 自分で 用意した スタックを 使った 繰り返しで 書いてください
例では、null です。
入力と出力の例
例 1
小さい
入力
root = [6, 3, 9, 1, 4, null,
11]
k = 3出力
4例 2
2 の
入力
root = [5, 2, 8, null, 3]
k = 4出力
8例 3
節が 1 つだけの木です。
入力
root = [7]
k = 1出力
7面接での聞かれ方
面接では、
- 「二分探索木の
中で、 k 番目に 小さい 値を 返してください」 - 値を
全部集めて 並べ替える 書き方を 答えると、 「二分探索木の 決まりを 使えていますか?」 「k が 小さい とき、 全部読む必要が ありますか?」と 聞き返されます - 「再帰を
使わずに 書けますか?」と、 繰り返しの 書き方を 求められる こともあります
二分探索木の
アルゴリズムのチートシートの「再帰と木」に、この型の要点を表とコードでまとめています。
まず 考える手順
段 1
まずk - 1 番目を
段 2
二分探索木では、k 個目にk 個目で
段 3
中順の
段 4
スタックに
解答
Python
Python
def kth_in_bst(root, k):
stack = []
node = root
while True:
while node:
stack.append(node)
node = node.left
node = stack.pop()
k -= 1
if k == 0:
return node.val
node = node.rightJavaScript
JavaScript
function kthInBst(root, k) {
const stack = [];
let node = root;
while (true) {
while (node !== null) {
stack.push(node);
node = node.left;
}
node = stack.pop();
k--;
if (k === 0) {
return node.val;
}
node = node.right;
}
}Go
Go
func kthInBst(
root *TreeNode, k int,
) int {
stack := []*TreeNode{}
node := root
for {
for node != nil {
stack = append(
stack, node,
)
node = node.Left
}
last := len(stack) - 1
node = stack[last]
stack = stack[:last]
k--
if k == 0 {
return node.Val
}
node = node.Right
}
}外のk は 1 以上 n 以下なので、k が 0 に
計算量
- 時間は O(h + k) です。
h は 木の 高さです。 最初に 左の 端まで h 段下り、 そこから k個取り出すまでに、スタックに 積む節と 取り出す節が それぞれ高々 h + k 個です。 最も 悪い 場合は O(n) です - 使う
記憶は O(h) です。 スタックには、 根から 今の 節までの 道の 上の 節しか 積まれません。 木が 片側に 伸びきると h は n に なり、 O(n) です
よく ある間違い
- 数える
番号を 1 つずらす。 kは 1 から数えます。 0 から 数える 番号と 混ぜると、 1 つ隣の 値を 返します。 例 3 のように kが 1 のとき、 いちばん 小さい 値が 返るかで 確かめます - 取り出した
あと、 右の 子へ 移り忘れる。 取り出した 節の 右の 部分木には、 その節の 次に 小さい 値が 入っています。 右へ 移らずに 次を 取り出すと、 右の 部分木の 値を 飛ばします - 左の
端まで 下りきらない。 左の 子を 1 つだけ 積んで 止めると、 さらに 左に ある 小さい 値より 先に、 大きい値を 読んでしまいます。 左が 無くなるまで積みます - 全部読んでから選ぶ。
中順に 読んで 並びに 全部入れてから k - 1番目を返すと、 答えは 合いますが、 kが小さくても 全部の 節を 読み、 記憶も O(n) 使います
解答を動かした版 Python 3.12.14Node.js 22.23.4Go 1.24.6確認日 2026年10月30日
面接での 話し方の例
書き始める
「全部集めて
並べ替えると O(n log n) です。 二分探索木は 左、 自分、 右の 順に 読むと 小さい 順に なるので、 その順に 読みながら 数えて、 k個目で止めます。 再帰の 代わりに、 左へ 下りながら節を スタックに 積み、 取り出したら 右の 子へ 移る 形で 書きます。 時間は O(h + k)、 記憶は 木の 高さ分の O(h) です。」
書き終えたら、
「例 1 で
たどります。 6、 3、 1 と 左へ 積んで、 1 を 取り出して 1 個目です。 1 に 右は 無いので、 次は 3 を 取り出して 2 個目、 3 の 右の 4 へ 移ります。 4 を 積んですぐ 取り出し、 これが 3 個目なので 4 を 返します。 6 より 右は 読みません。」
