令和7年度 基本情報技術者試験 科目B 問4の解説|条件式が真になる回数を数える

基本情報技術者試験

令和7年度 科目B 公開問題 問4擬似言語・配列・文字列照合最終更新 2026-09-04

令和7年度の科目B、その4問目です。訊かれているのは、この関数が何を作るかではなく、ある1行の条件式が「真となる」回数です。プログラムの意味が分かっても、数え方でつまずく問題です。

出題

まず原文のまま読んでみてください。記号の読み方は次の節にまとめてありますので、読めなくてもここでは問題ありません。

出典:令和7年度 基本情報技術者試験 科目B 公開問題 問4

次の記述中の   に入れる正しい答えを,解答群の中から選べ。ここで,配列の要素番号は1 から始まる。

関数search は,二つの文字型の配列を,それぞれ引数data 及びkey で受け取り,data から,key の要素の並びと同じ並びを全て探し,その先頭の要素番号を全て格納した配列を返す。見つからなければ,要素数0 の配列を返す。

関数search をsearch({“a”, “b”, “a”, “b”, “c”, “a”, “b”, “c”}, {“a”, “b”, “c”}) として呼び出すと,/*** β ***/の行の条件式が真となる回数は   回である。

〔プログラム〕

/* keyは,要素数1以上の配列である */
○整数型の配列: search(文字型の配列: data, 文字型の配列: key)
  整数型: i, j, lenData, lenKey
  整数型の配列: result ← {}  // 要素数0の配列

  lenData ← dataの要素数
  lenKey ← keyの要素数

  /* (lenData - lenKey + 1) が0以下のときは繰返し処理を実行しない */
  for (i を 1 から (lenData - lenKey + 1) まで 1 ずつ増やす)
    for (j を 1 から lenKey まで 1 ずつ増やす)  // α
      if (data[i + j - 1] が key[j] と等しい)  /*** β ***/
        if (j が lenKey と等しい)
          resultの末尾 に iの値 を追加する
        endif
      else
        αの行から始まる繰返し処理を終了する
      endif
    endfor
  endfor
  return result

解答群

ア 1イ 2ウ 3エ 4オ 5

カ 6キ 7ク 8ケ 9コ 10

答えだけ先に見る

正解は ク(8回)。ただし、この記事は解答群を見ずに数える順で進みます。解答群は 1 から 10 の数字が並んでいるだけなので、見比べても何も決まりません。

この問題に出てくる記号と言葉

読めない記号があったときだけ開いてください。先に全部読む必要はありません。

擬似言語の記号と言葉 10コ の読み方をひらく
書き方 読み方
← 左に書き込む。lenData ← dataの要素数 なら、右で求めた値を lenData に入れます
○整数型の配列: search(…) 行頭の ○ はここから1つのまとまった処理が始まるという印。整数型の配列 は、そのまとまりが最後に作り出すものの種類です
整数型: i, j, lenData, lenKey 使う箱の名前をまとめて宣言しているだけの行。ここでは何も起こりません
/* … */
// …
どちらもコメント(人が読むための覚え書き)で、実行されません。この問題では、その覚え書きに付けた α と β という行の名前が本文から参照されています
search(文字型の配列: data, 文字型の配列: key) かっこの中は呼ぶときに渡された配列が入る変数です。search({"a", …}, {"a", "b", "c"}) と呼べば、data が1つ目、key が2つ目になります
dataの要素数 配列 data の枡の数。この呼び出しでは 8 です
data[3] 配列 data の 3番目の枡。角かっこの中は要素番号で、1 から数えます。data[i + j - 1] のように式も書けます
return そこで関数を終えて、値を返すという意味です。return result なら、配列 result を返して終わります
{} 要素数0の配列。枡が1つも無い状態です
resultの末尾 に iの値 を追加する 配列 result のうしろに枡を1つ増やして、そこに i の値を入れます
αの行から始まる繰返し処理を終了する // α と書かれた 内側の for だけを、その場でやめます。外側の for は続きます

コードを読む ── どこまで、何と何を、いつやめる

この問題は空欄がプログラムの外にあります。だから「何を数えるのか」は、コードを読まないと決まりません。注釈を付けて、原文をもう一度置きます。

○整数型の配列: search(文字型の配列: data, 文字型の配列: key)

見つけた先頭の要素番号を並べた配列を返す

整数型: i, j, lenData, lenKey

使う箱の宣言。ここでは何も起こらない

整数型の配列: result ← {}

見つけた番号を入れる。はじめは空

lenData ← dataの要素数

この呼び出しでは 8

lenKey ← keyの要素数

この呼び出しでは 3

for (i を 1 から (lenData - lenKey + 1) まで 1 ずつ増やす)

i を 1 から 8 - 3 + 1 = 6 まで動かす

for (j を 1 から lenKey まで 1 ずつ増やす) // α

j を 1 から lenKey(=3)まで。この間 i は動かない

if (data[i + j - 1] が key[j] と等しい) /*** β ***/

ここが数える行。data[i + j - 1] と key[j] が等しければ真

if (j が lenKey と等しい)

β が真のときだけ来る。真になるのは最後の j まで届いたときだけ

resultの末尾 に iの値 を追加する

先頭の要素番号を記録する

endif

 

else

 

αの行から始まる繰返し処理を終了する

α は内側の for の名前。内側だけをここで終わらせる

endif

 

endfor

 

endfor

 

return result

見つけた番号を並べて返す(中身はこれから数えます)

※ 右側の注釈は当サイトで書き加えたものです。左のプログラムは原文のままですが、説明に使わないコメント2行は省いています(全文は上の〔プログラム〕にあります)。

数えるのに要るのは、ここから読み取る3つだけです。

① data[i + j - 1] と key[j] ── i を止めて j を動かす

内側の for が動かすのは j だけで、1 から lenKey(=3)まで。そのあいだ i は変わりません。まず i = 1 で、添字の式に数字を入れて、配列の上で1つずつ見ていきます。

添字の式 data[i + j - 1] を、配列の上でたどる

上=配列 data(枡の番号は要素番号)/下=配列 key を i 番に重ねたもの(枡の番号は j)。琥珀=その j で組になる枡。「次へ」で1つずつ進みます。

j = 1 → data[1 + 1 - 1] = data[1] と key[1]

data

1a

2b

3a

4b

5c

6a

7b

8c

key

1a

2b

3c

data の 1番(a)と、key の 1番(a)が組になりました。

j = 2 → data[1 + 2 - 1] = data[2] と key[2]

data

1a

2b

3a

4b

5c

6a

7b

8c

key

1a

2b

3c

data の 2番(b)と、key の 2番(b)が組になりました。

j = 3 → data[1 + 3 - 1] = data[3] と key[3]

data

1a

2b

3a

4b

5c

6a

7b

8c

key

1a

2b

3c

data の 3番(a)と、key の 3番(c)が組になりました。

i を 2 にすると、3組そろって1つ右へ

data

1a

2b

3a

4b

5c

6a

7b

8c

key

 

1a

2b

3c

data[2 + j - 1] なので、組になる相手は 2番・3番・4番。key ごと右へずれました。i が置きはじめる番号、j がkey の中の何番目かです。

i = key を置きはじめる番号 / j = key の中の何番目か

ここで見ているのは式が何と何を組にするかだけです(実際に比べた結果がどうなるかは ③ で決まります)。式が言っているのは、key を i 番の位置に置いて、上下で見比べる、ということです。

② 外側の for ── i はどこまで動かせるか

i は key を置きはじめる番号だと分かりました。では、どこまで動かせるでしょうか。置けなくなるところを見ます。

i を大きくしていくと、どこで置けなくなるか

上=配列 data(枡の番号は要素番号)/下=配列 key を i 番に重ねたもの(枡の番号は j)。琥珀=組になる枡/赤い破線=data の外にはみ出す枡

i = 6 ── ちょうど収まる

data

1a

2b

3a

4b

5c

6a

7b

8c

key

 

 

 

 

 

1a

2b

3c

key の 3番の真上が data の 8番=最後の枡。ぴったり収まりました。

i = 7 ── はみ出す

data

1a

2b

3a

4b

5c

6a

7b

8c

key

 

 

 

 

 

 

1a

2b

3c

key の 3番の上に、data の枡がありません(data は 8番まで)。7番からは置けません。

置ける最後は 6番 ── data の 8 枡から、key の 3 枡ぶんを引いて +1

data が 8 枡、key が 3 枡。key の3枡ぶんの場所が要るので、置ける最後は 8 - 3 + 1 = 6 番です。これが出題に書いてある (lenData - lenKey + 1) の正体です。

上限は、式のまま持って進まずに、ここで数字にしておきます。1つずれると、あとの数え方が全部ずれます。

③ else ── そろわなかったら、内側だけ抜ける

比べた結果が偽のとき、else の下は αの行から始まる繰返し処理を終了する の1行です。α は内側の for に付けた名前なので、終わるのは内側だけ。この記事では、これを「打ち切り」と呼びます。

外側の for は endfor まで生きているので、そのまま続きます。i が1つ増えて、j はまた 1 から始まります。

最後の j まで届いた場合も同じです。result に番号を足したあと、内側の for がふつうに終わって、外側が次の i へ進みます。見つかっても、そこで止まりません。だから i はいつも 1 から 6 まで動きます。

i を 1 から 6 まで動かして、真になった回数を数える

数えるのは /*** β ***/ の行が真になった回数です。同じ行に来た回数ではありません(偽のときも来ます)。β は内側の for の中にあるので、数えるのは「上下を見比べた回数」のうち「そろったほう」だけ ── 位置の数でも、見つかった並びの数でもありません。

数えるのはこの中の1行です(〔プログラム〕からの抜粋)

    for (j を 1 から lenKey まで 1 ずつ増やす)  // α
      if (data[i + j - 1] が key[j] と等しい)  /*** β ***/
        if (j が lenKey と等しい)
          resultの末尾 に iの値 を追加する
        endif
      else
        αの行から始まる繰返し処理を終了する
      endif
    endfor

※ 上の〔プログラム〕からの抜粋です(1字も変えていません)。

読み取った3つを、i = 1 から 6 まで当てはめます。以下、i のことを「開始位置」と呼びます(key を置きはじめる番号だからです)。

6つの開始位置を、1つずつ

緑=そろった(β が真)/赤=そろわなかった(β が偽)/灰=打ち切ったので、比べずに終わった。「次へ」で開始位置を1つずつ進みます。

i = 1 ── 1番から重ねる

data

1a

2b

3a

4b

5c

6a

7b

8c

key

1a

2b

3c

a=a 真、b=b 真、a と c はそろわない → 打ち切り。真は 2 回

i = 2 ── 2番から重ねる

data

1a

2b

3a

4b

5c

6a

7b

8c

key

 

1a

2b

3c

1つ目から b と a でそろわない → 打ち切り。真は 0 回

i = 3 ── 3番から重ねる

data

1a

2b

3a

4b

5c

6a

7b

8c

key

 

 

1a

2b

3c

3つともそろいました。j が lenKey(3)まで来たので、result に 3 を追加します。真は 3 回

i = 4 ── 4番から重ねる

data

1a

2b

3a

4b

5c

6a

7b

8c

key

 

 

 

1a

2b

3c

b と a でそろわない → 打ち切り。真は 0 回

i = 5 ── 5番から重ねる

data

1a

2b

3a

4b

5c

6a

7b

8c

key

 

 

 

 

1a

2b

3c

c と a でそろわない → 打ち切り。真は 0 回

i = 6 ── 6番から重ねる

data

1a

2b

3a

4b

5c

6a

7b

8c

key

 

 

 

 

 

1a

2b

3c

3つともそろいました。result に 6 を追加します。真は 3 回

開始位置ごとの、真になった回数 ── 2・0・3・0・0・3

回数を決める

数えていたのは、この1行が真になった回数でした。

数えた行(〔プログラム〕からの抜粋)

      if (data[i + j - 1] が key[j] と等しい)  /*** β ***/

※ 上の〔プログラム〕からの抜粋です(1字も変えていません)。

開始位置ごとに出した数を、そのまま足します。

β が真となる回数

2 + 0 + 3 + 0 + 0 + 3 = 8 回

足しているのは真になった回数だけです。β の行に来たのは 12 回(真8 + 偽4)ですが、そろわなかった 4 回は入れません。設問が訊いているのは「条件式が真となる回数」だからです。

本番の手順 ── 「何回」を訊かれたら

  1. 何を数えるのかを、設問の文から1つに絞る。
    「条件式が真となる回数」なら、偽は数えません。行を通った回数でも、ループが回った回数でもありません。ここを取りちがえると、全部数え直しになります。
  2. くり返しの上限を、先に数字にする。
    この問題なら lenData - lenKey + 1 を 6 と出しておきます。上限を式のまま持って進むと、必ずどこかで1つずれます。
  3. 途中で抜ける行があるかを探す。
    あれば、「1周あたり何回」が周ごとに変わります。かけ算で片づけられないので、1周ずつ数えるしかありません。

ここで初めて解答群を見る

数えた答えは 8。解答群で 8 は ク です。

答え合わせ ── 通して数え直す

手で数えたときに数え落としが無かったかを、頭から通して確かめます。β の行に来るたびに1コマ進み、真になったときだけ右端の数が増えます。数える行ではない if (j が lenKey と等しい) は、コマを分けていません(β が真のたびに通ります)。

1回ずつ追う β の行を通る12回

出典:令和7年度 科目B 公開問題 問4


ループ開始前

配列

▲ いま読んでいる▲ いま書いた

いま計算していること

まだ計算していません

変数の状態

トレース表(進めると1行ずつ積み上がります)

正解は ク

β の条件式が真となる回数は 8 回。

解答群にある 6・2・4 は、どれも別の行を数えた値でした(外側の for/見つかった数/偽になった回数)。数えるのは /*** β ***/ の行が真になったときだけです。

同じ考え方で解く練習問題

同じプログラムに、別の呼び出しを与えます。key の長さも変わります。

当サイトで作った類題です(IPAの出題ではありません)

上と同じ search を search({"a", "b", "a", "a", "b"}, {"a", "b"}) として呼び出すと、/*** β ***/ の行の条件式が真となる回数は何回ですか。

「何回」を訊く問題を見分ける

解答群が数字だけの回は、見比べても何も決まりません。数えるしかない、という合図です。

そのときいちばん効くのが、上の「本番の手順」の3つ目です。途中で抜ける行(繰返し処理を終了する)があると、1周あたりの回数が周ごとに変わります。この1行を見落とすと、6 × 3 = 18 のようなかけ算で答えを作ってしまい、解答群に無い数が出てきます。

次に読む

この記事で引用した資料

いずれも独立行政法人情報処理推進機構(IPA)が公表したものです。IPAは公表済みの試験問題について、教育目的での使用に許諾および使用料を不要としていますが、著作権は放棄していません。本記事では問題文を改変せずに引用しています。

「search({“a”,”b”,”a”,”a”,”b”}, {“a”,”b”}) のときの回数を問う練習問題」は当サイトのオリジナルです。

Copied title and URL