2 本の 指で 2 人とも 空いている 日を求める
2 人それぞれの、
海外で定番の問題リスト 4 本には入っていません
問題
2 人の[初日, 最終日] のa と b で
aもbも、初日の 小さい 順に 並んでいて、 同じ 並びの 中の どの 2 つも 重ならず、 接してもいません - 片方の
最終日と、 もう 片方の 初日が 同じなら、 その 1 日は 2 人とも 休みです。 [t, t]の 1 日の範囲として返します aとbは、どちらも 空の ことがあります。 2 人とも 休みの 日が 無ければ、 空の 並び []を返します- どの
組も、 初日は 最終日以下です aとbの長さは どちらも 0 以上 1000 以下、 値は どれも 0 以上 1000000000 以下です
入力と出力の例
例 1
b の [3, 9] は a の 2 つの
例 2
a のb の
例 3
b のa の 2 つの
面接での聞かれ方
面接では、
- 「2 人の
空いている 時間の 一覧が あります。 2 人とも 空いている 時間を 全部出してください」 - 「一覧は並んでいますか」と
聞くと、 「並んでいて、 同じ 人の 中では 重なりません」と 返ってくるのが ふつうです - 書き終えた
あとに 「3 人以上 なら どうしますか」と、 続きを 聞かれる こともあります
両端を
ヒント
まだ開いていません
付箋は 3 枚。下の段ほど答えに近づきます
ヒント 2
ヒント 3答えに近い
アルゴリズムのチートシートの「配列と文字列」に、
関わる学び
配列と
まず 考える手順
段 1
素直にa のb の
段 2
2 つの[s1, e1] と [s2, e2] のmax(s1, s2)、min(e1, e2) の
段 3
両方の
解答
Python
Python
def interval_intersections(a, b):
out = []
i = j = 0
while i < len(a) and j < len(b):
s = max(a[i][0], b[j][0])
e = min(a[i][1], b[j][1])
if s <= e:
out.append([s, e])
if a[i][1] < b[j][1]:
i += 1
else:
j += 1
return outJavaScript
JavaScript
function intervalIntersections(
a, b
) {
const out = [];
let i = 0;
let j = 0;
while (
i < a.length && j < b.length
) {
const s = Math.max(
a[i][0], b[j][0],
);
const e = Math.min(
a[i][1], b[j][1],
);
if (s <= e) {
out.push([s, e]);
}
if (a[i][1] < b[j][1]) {
i++;
} else {
j++;
}
}
return out;
}Go
Go
func intervalIntersections(
a, b [][]int,
) [][]int {
out := [][]int{}
i, j := 0, 0
for i < len(a) && j < len(b) {
s := max(a[i][0], b[j][0])
e := min(a[i][1], b[j][1])
if s <= e {
out = append(out,
[]int{s, e})
}
if a[i][1] < b[j][1] {
i++
} else {
j++
}
}
return out
}最終日がb の
計算量
- 時間は O(m + n) です。
1 回まわる たびに どちらかの 指が 1 つ 進むので、 まわる 回数は m + n 以下です - 使う
記憶は、 答えの 並びを 除けば O(1) です。 答えの 並びは 最悪 m + n - 1 本の 範囲を持ちます - 全部の
組を 調べる 書き方の O(mn) より 速いのは、 並んでいて 重ならない ことを 使っているからです
よく ある間違い
- 1 日だけの
重なりを落とす。 重なりが ある 条件を s < eと書くと、 例 2 の [6, 6]が答えに 入りません。 両端を 含むので s <= eです - 重なった
ときに 両方の 指を進める。 例 1 で [1, 4]と[3, 9]が重なった あと 両方を 進めると、 [3, 9]と[8, 12]の重なり [8, 9]を落とします。 進めるのは 最終日が 早い方だけです - 初日の
早い方の 指を進める。 a = [[1, 10]]、b = [[2, 3], [5, 6]]で初日の 早い [1, 10]を進めると、 aが尽きて [5, 6]を落とします。 範囲が 「もう要らない」と 分かるのは、 最終日で 比べた ときだけです - 空の
並びを 特別扱いし忘れる。 先頭を 読んでから 回す 書き方だと、 aかbが空の ときに 止まります。 この 解き方は、 ループの 条件で 両方の 長さを 見ているので 空でも動きます
解答を動かした版 Python 3.14.7Node.js 24.22.1Go 1.24.2確認日 2026年11月8日
面接での 話し方の例
書き始める
「2 つの
範囲の 重なりは、 初日の 大きい方から 最終日の 小さい 方までで、 初日が 最終日以下なら 重なっています。 両方の 並びに 指を 置き、 指した 2 つの 重なりを 調べてから、 最終日が 早い方の 指を 進めます。 最終日が 早い方の 範囲は、 相手の 後ろの 範囲とは もう 重ならないからです。 時間は O(m + n)、 答えの 他の 記憶は O(1) です。」
書き終えたら、
「例 1 で
たどります。 [1, 4]と[3, 9]は[3, 4]が重なり、 4 が 早いので aを進めます。 [8, 12]と[3, 9]は[8, 9]、9 が 早いので bを進めます。 [8, 12]と[11, 16]は[11, 12]、12 が 早いので aを進めます。 [15, 20]と[11, 16]は[15, 16]、16 が 早いので bを進め、 bが尽きて 終わりです。 答えは [[3, 4], [8, 9], [11, 12], [15, 16]]です。」