Paiza スキルチェック過去問題(PHP編) 日別訪問者数の最大平均区間 ~ランク B 相当~ 解いてみた。


はじめに

Paizaにて日別訪問者数の最大平均区間 (paizaランク B 相当)を解いてみました。

本番問題の解答・解説はNGですが、こちらに関しては、公開していいそうなのでまとめておきます。

(回答をPaizaでは再度閲覧できないため、備忘録的目的もあります。)

また、事前知識として標準入力の基本を知っておく必要がありますが、今回は割愛します。以下が参考になるかと思います。

https://paiza.jp/works/mondai/skillcheck_archive/max_range?language_uid=php

日別訪問者数の最大平均区間 (paizaランク B 相当)


以下が問題のリンクです。詳細はこちらでご確認ください。

https://paiza.jp/works/mondai/skillcheck_archive/max_range?language_uid=php

※問題文抜粋※

あなたは、とあるウェブサイトを管理していました。
ある連続したk日間、このウェブサイトでキャンペーンを行ったのですが、いつからいつまでの期間に行ったかを忘れてしまいました。

幸い、ウェブサイトを運営していた全n日分のアクセスログが残っており、1日ごとの訪問者数が分かっています。
とりあえず、連続するk日の中で、1日あたりの平均訪問者数が最も多い期間を、キャンペーンを行った期間の候補だと考えることにしました。

n日分の訪問者数のリストとキャンペーンの日数kが入力されるので、キャンペーンを行った期間の候補数と、候補の中で最も早い開始日を出力してください。


実際に入力される値:
5 3
1 2 3 2 1

ケースパターン3(躓いた部分メモ):
100 10
2 7 1 1 5 7 0 7 5 8 4 9 9 0 9 6 5 2 3 2 9 8 5 2 10 10 9 4 3 0 9 9 4 2 7 6 6 3 4 8 0 6 4 2 6 1 8 7 0 0 8 10 6 1 2 10 0 9 9 0 4 4 1 4 10 3 6 8 7 6 2 2 6 7 0 5 1 4 0 7 2 7 4 0 2 4 5 8 9 6 3 5 3 9 7 5 6 7 3 4

期待される出力:
1 2

ちなみに他ケースパターンはpaiza.ioで実行テストできます。

ブラウザ上で且つ無料で使えるのでかなり便利です◎

https://paiza.io/ja


失敗例

解答コード:
<?php
    // $nに全日数5、$kにキャンペーン日数3 を代入
    fscanf(STDIN, "%d %d", $n, $k);
    $visiter = fgets(STDIN);
    // 数字で配列として1 2 3 2 1を代入
    (int)$visiters = explode(" ",$visiter);
    // k日分の訪問者数の和を必要な回数分求める
    $slice_visiters = [];//[6,7,6]
    for($i=0;$i<$n-$k+1;$i++){
    // 全訪問者数からキャンペーン日数分の値のみ取り出す
    $slice_visiter = array_slice($visiters,$i,$k);
    //キャンペーン日数分の値の合計を出す
    $slice_visiter = array_sum($slice_visiter);
    //$slice_visitersへ配列を代入。配列に配列を代入してる。
    array_push($slice_visiters,$slice_visiter);
    }
    //[6,7,6]を676に結合
    $join = implode('', $slice_visiters);
    $max = max($slice_visiters);//7
  //substr_count( 検索対象の文字列, 検索する文字列 )
    $count = substr_count( $join, $max );
  //mb_strpos( 検索対象の文字列, 検索する文字列 )※0からカウントされる
    $position = mb_strpos( $join, $max );
    $ask_position = $position+1;
    echo "$count $ask_position";
?>

約2時間の格闘の末、なんとかsuccessまで持っていきました。

絶対コードぐちゃぐちゃ(じぶんもよくわからない)。

もはや執念。。。

ところがどっこい。。。

不正解でした。

implode関数で結合しましたがよくよく考えたら、例えばmax値が15のときだと、1,5の配列も15としてみなされてカウントされちゃうのでだめですね。。。2桁の数字があると位置もずれるし。。。値が2桁になるケースを考えていなかった。。。

Oh my god!!

正解例

以下が正解例になります。

解答コード:
<?php
    fscanf(STDIN, "%d %d", $n, $k);
    $visiter = fgets(STDIN);
    (int)$visiters = explode(" ",$visiter);
    $slice_visiters = [];//[4,13,15,13]
    for($i=0;$i<$n-$k+1;$i++){
    // 全訪問者数からキャンペーン日数分の値のみ取り出す
    $slice_visiter = array_slice($visiters,$i,$k);
    //キャンペーン日数分の値の合計を出す
    $slice_visiter = array_sum($slice_visiter);
    //$slice_visitersへ配列を代入。配列に配列を代入してる。
    array_push($slice_visiters,$slice_visiter);
    }
    //数字が連結しないようにカンマで区切る
    $join = implode(',', $slice_visiters);
    //配列の中の最大値を取得
    $max = max($slice_visiters);
    //最大値が出現する回数をカウント 
    $count = substr_count( $join, $max );
    // 配列の中で最大値の最初の位置をキー値で取得※0からカウントされるので+1
    $position = (int)array_search($max,$slice_visiters)+1;
    echo "$count $position";
?>

失敗例のコードから諦めきれず、約1時間格闘した末なんとか正解まで辿り着きました。

ポイントは最大値が2桁の数字の際に、1桁の数字が連結してカウントされないように,(カンマ)でimplodeする際区切ったことと、array_search関数を使用して、配列の位置をキーで取得したことです。

参考になれば幸いです。

おわりに

値の数が多くなるとプログラミングを使うメリットを感じます。

ちゃんとPaizaランクBになれるよう頑張ります。

関連リンク

Paiza スキルチェック見本問題(PHP編)まとめ ~ランクC相当~
https://chobimusic.com/paiza_skillcheck_c/

Paiza スキルチェック見本問題(PHP編)まとめ ~ランクD相当~
https://chobimusic.com/paiza_skillcheck_d/

Paiza 標準入力セット(PHP編)まとめ ~ランクD相当~
https://chobimusic.com/paiza_standard_input/