長さを 決めた窓で 並べ替えた 言葉が 文の 中に 続けて 入っているか調べる
言葉 p の
海外で定番の問題リスト 4 本には入っていません
問題
英小文字だけのp と、s をp のs のtrue、false を
- 並べ替えでは、
文字の 種類と 数を そのまま 使います。 同じ 文字が 2 つ あれば、 2 つとも使います sの中で 飛び飛びに 拾った 文字は 数えません。 続いた 部分だけを見ます pとsの長さは、 どちらも 1 以上 10000 以下です。 pがsより長いこともあります
入力と出力の例
例 1
s の"eat" は、"tea" の
例 2
s に a も b も
例 3
a が 2 つのs の "baa" は、
面接での聞かれ方
面接では、
- 「s が、
p の 並べ替えの どれかを 部分文字列として 含むか 判定してください」 - 「文字は
英小文字だけですか?」と、 自分から 確かめるかを 見られます - 書き終えた
あとに 「1 回ずらすたびに 26 文字を 比べずに 済みませんか?」と 広げられる こともあります
並べ替えを
ヒント
まだ開いていません
付箋は 4 枚。下の段ほど答えに近づきます
ヒント 2
ヒント 3
ヒント 4答えに近い
アルゴリズムのチートシートの「配列と文字列」に、
関わる学び
配列と
まず 考える手順
段 1
2 つのs のp とp と
段 2
素直にp の
段 3
隣り合った 2 つの
段 4
窓のp のp が s よりfalse を
解答
Python
Python
from collections import Counter
def has_shuffled(p, s):
m = len(p)
if m > len(s):
return False
ref = Counter(p)
win = Counter(s[:m])
if win == ref:
return True
for i in range(m, len(s)):
win[s[i]] += 1
win[s[i - m]] -= 1
if win == ref:
return True
return FalseJavaScript
JavaScript
function hasShuffled(
p,
s
) {
const m = p.length;
const n = s.length;
if (m > n) return false;
const ref = Array(26).fill(0);
const win = Array(26).fill(0);
const idx = (c) =>
c.charCodeAt(0) - 97;
for (let i = 0; i < m; i++) {
ref[idx(p[i])]++;
win[idx(s[i])]++;
}
const same = () => win.every(
(v, j) => v === ref[j]
);
if (same()) return true;
for (let i = m; i < n; i++) {
win[idx(s[i])]++;
win[idx(s[i - m])]--;
if (same()) return true;
}
return false;
}Go
Go
func hasShuffled(
p string,
s string,
) bool {
m := len(p)
if m > len(s) {
return false
}
var ref, win [26]int
for i := 0; i < m; i++ {
ref[p[i]-'a']++
win[s[i]-'a']++
}
if win == ref {
return true
}
for i := m; i < len(s); i++ {
win[s[i]-'a']++
win[s[i-m]-'a']--
if win == ref {
return true
}
}
return false
}ref が p のwin がs のs[i] をs[i - m] を'a' は、a が 0、z が 25 にCounter と Go の== でCounter は、
計算量
- 時間は O(26 × n + m) です。
窓を n 回ずらし、 1 回に 26 個を 比べます。 文字の 種類が 決まっているので、 O(n + m) と 言ってもかまいません - 使う
記憶は O(1) です。 26 個の 表を 2 つ 持つだけです - 段 2 の
数え直す 書き方は O(n × m)、 並べ替えを 全部作る 書き方は m の 階乗に 比例し、 とても 間に 合いません
よく ある間違い
pの並べ替えを 全部作ってから探す。 長さ 10 で 360 万通りを 超え、 すぐ間に 合わなくなります。 文字の 数で比べます - 文字の
種類だけを 比べて、 数を 比べない。 例 3 の "aab"は a が 2 つです。種類だけなら、 a が 1 つで b が 2 つの "abb"のような窓でも 合ってしまいます - 窓から
出ていく 文字を 引き忘れる。 窓が 伸び続け、 例 2 のように 文字が 飛び飛びに ある sでもtrueを返します pがsより長いかを 確かめずに、 最初の 窓を作る。 sの先頭 m 文字を 読む ところで、 Go は 範囲の 外を 読んで 止まり、 JavaScript も 無い 文字を 読んで エラーに なります。 最初に falseを返します
解答を動かした版 Python 3.14.7Node.js 24.22.1Go 1.24.2確認日 2026年11月8日
面接での 話し方の例
書き始める
「並べ替えの
関係は、 文字ごとの 数が 同じかで 決まります。 s の 上に p と 同じ 長さの 窓を 置き、 1 文字ずつ右へずらしながら、 入った 文字を 足し、 出た 文字を 引きます。 毎回 26 個の 表を p の 表と 比べ、 同じなら true です。 時間は O(n)、 記憶は 26 個の 表 2 つです。」
書き終えたら、
「例 1 で
たどります。 p の 表は t、 e、 a が 1 つずつです。 窓は gre、 rea と 進み、 どちらも g や r が 入っていて 違います。 次の eat で e、 a、 t が 1 つずつに なり、 表が 同じなので true を 返します。」