FE Study
FE Study メニュー

学習記録はこのブラウザー内に保存されます。

ホーム手順で学ぶ実習
ログイン不要・無料で学習

WORKED CASE・約25分

連続達成回数を求める擬似言語を、一行ずつ追跡する

配列のしきい値判定から最長の連続回数を求めます。初期値、更新順、添字、空配列、最終要素を同じ手順で確かめる科目B向けの独自演習です。

公開・確認: / 作成:FE Study編集部

この実習でできるようになること

  • 現在の連続回数と、これまでの最大回数を分けて追跡できる。
  • ループ条件と添字の範囲から、最後の要素と範囲外アクセスを確認できる。
  • 通常のデータで隠れる誤りを、境界値の小さな入力で見つけられる。

前提と課題

架空の学習記録アプリで、1日に取り組んだ問題数を配列に記録しています。1日18問以上なら目標達成とし、最も長く連続達成した日数を求めます。配列の要素は0以上の整数、添字は1から始まり、要素数をnとします。

この演習の擬似言語では、whileは条件を先に評価し、偽なら本体を実行しません。代入記号←は右辺を評価して左辺へ設定します。配列の範囲外参照は許さず、空配列のときnは0です。特定のプログラミング言語の添字規則を持ち込まず、ここで示した条件を使ってください。

入力配列a
{12, 18, 18, 9, 20, 21}
要素数としきい値
n=6、target=18、達成条件はa[i]≧target
current
今読んだ日まで連続して達成している日数
best
これまでに見つけた最長の連続達成日数

自分で求めてみよう

次の処理が返すbestを求め、各反復後のi、current、bestを追跡してください。続いて、空配列、1要素、配列末尾まで連続する場合に正しく動く理由を説明しましょう。

途中の式や表も紙に書いてから、次の手順と照合してください。

途中の手順と検算

1. 変数の役割を決めてから、処理全体を読む

currentとbestは似ていますが、更新条件が異なります。currentは未達成の日を読むと0に戻ります。bestは過去の最長記録なので、その後に未達成の日が来ても減らしません。この意味を先に書くと、「どちらも毎日リセットする」といった誤りを見つけやすくなります。

i ← 1 current ← 0 best ← 0 while (i ≦ n) if (a[i] ≧ target) current ← current + 1 else current ← 0 endif if (current > best) best ← current endif i ← i + 1 endwhile return best

最大値の更新は、達成判定でcurrentを変更した後に行います。比較がcurrent > bestでもcurrent ≧ bestでも、bestの数値だけを返すこの処理では結果は同じです。ただし、最長区間の開始日も記録する拡張では、同点時に更新するかが「最初の区間」「最後の区間」の違いになります。

2. 一回の反復で変わる値を、実行順どおり記録する

初期値はi=1、current=0、best=0です。1日目の12は未達成なのでcurrentは0のままです。2日目の18は「以上」に含まれるのでcurrentが1、bestも1になります。3日目も18なのでcurrentが2、bestが2へ進みます。比較対象の18を除外してしまうと、この途中経過が変わります。

4日目の9ではcurrentだけを0へ戻します。bestは2を保ちます。5日目の20から新しい連続区間が始まり、6日目の21で再び長さ2になります。下表のiは、その行で参照した添字です。本体の最後ではiが1増えるため、最終行の終了時点ではi=7になります。

2. 一回の反復で変わる値を、実行順どおり記録するの確認表
参照したia[i]達成判定更新後current更新後best
112偽00
218真11
318真22
49偽02
520真12
621真22

3. 反復の前後で成り立つ性質を使って、更新順を検算する

i番目を処理した直後、currentは「i番目で終わる連続達成区間の長さ」、bestは「1番目からi番目までの最長連続達成区間の長さ」です。達成なら昨日の連続区間に1を足し、未達成ならその日で区間が切れるため0にする、と考えればcurrentの更新を説明できます。

新たな最長記録が生まれる可能性があるのは、今回のcurrentが以前のbestを超える場合だけです。従ってcurrent更新後に最大値を比較すれば、同じ性質が次の反復でも保たれます。表を埋めるだけでなく、この説明ができると、配列が600要素になっても手順の正しさを考えられます。

4. 最初・最後・要素0件を、小さな入力で試す

空配列ならn=0なので、最初の条件1≦0は偽です。a[1]は参照されず、初期値best=0が返ります。1要素の{18}なら1回だけ実行して1、{17}なら0です。値がしきい値と等しいケースを含めると、≧を誤って>にした実装を検出できます。

末尾の取りこぼしには{4, 18, 19, 20}を使います。正解は3です。条件をi < nにするとi=4を処理せず2を返します。一方、元の6要素では最後を飛ばしても前半の最長2が残るので、戻り値だけでは誤りが見えません。通常例が通ったことと、境界が正しいことを分けて検証する必要があります。

4. 最初・最後・要素0件を、小さな入力で試すの確認表
入力期待するbest主に確かめること
{}0要素へ触れる前の終了判定
{18}11要素としきい値ちょうど
{17}0全て未達成の初期値
{4, 18, 19, 20}3最終要素を含む区間

5. 計算量と仕様変更の影響を説明する

各要素を一度だけ読み、反復の中では一定個数の比較・加算・代入を行います。従って時間計算量はO(n)、入力配列を除く追加領域はi、current、bestなどの一定個数なのでO(1)です。二つのifがあることを、二重ループと混同しないでください。

もし「最長の区間が何日目から始まったか」まで返したいなら、bestを更新した時点の開始添字i−current+1を記録できます。例えば3日目なら3−2+1=2です。同点で更新しない現在の>を使えば、最後の区間ではなく最初に見つかった最長区間を保てます。返す値が増えたら、同点時や空配列の仕様も追加してから変更します。

解答と、ここまでの要点

返すbestは2です。2〜3日目と5〜6日目に、どちらも2日間の連続達成区間があります。4日目にcurrentは0へ戻りますが、bestは2を保持します。

i≦nによってn番目まで読み、i=n+1になってから終了するため範囲外を参照しません。n=0では本体を一度も実行せず0を返します。

つまずいたときに確認すること

  • 「現在の連続区間」と「過去の最大区間」を同じ変数の意味として扱う。
  • 「18以上」を「18より大きい」と読み替えて、境界値を除外する。
  • 戻り値が合う通常例一つだけで、最終要素も処理したと判断する。
  • 最大値を更新する前後の順序や、添字を増やす位置を読み飛ばす。

条件が変わっても説明できますか?

選択後に結果と理由を確かめられます。解答は折りたたみからいつでも読めます。

元の配列で4番目の要素9を処理した直後のcurrentとbestはどれですか。

選んでから確認できます。確認問題は通常の演習記録には加算しません。

解答と理由を見る

解答:current=0、best=2

未達成で途切れたのでcurrentだけ0になります。過去に2日間の連続達成があった事実は消えないためbestは2を保ちます。

whileの条件を誤ってi < nにしました。入力{4, 18, 19, 20}で返す値と、正しい値の組合せはどれですか。

選んでから確認できます。確認問題は通常の演習記録には加算しません。

解答と理由を見る

解答:誤った処理は2、正しい値は3

i=1、2、3だけを処理し、最後の20へ到達する前に終了します。2番目と3番目の2日間しか数えないため2です。正しくは2〜4番目の3日間を数えます。

次の学習

手順を見ずにもう一度解き、以下の関連問題でも同じ考え方を使えるか確かめましょう。

参照資料とケースの範囲

計算条件、表、シナリオ、確認問題は本サイト独自のものです。用語と考え方の確認には以下の一次資料を使っています。実務では組織の手順や実際の製品仕様も確認してください。

教材の根拠・編集方針 / 誤り・改善点を連絡する