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

5日間のうちキャンペーンは3日間実施。

1日目1人 2日目2人 3日目3人 4日目2人 5日目1人

(ウェブサイトにしては訪問者数少なすぎじゃない・・・??)

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

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

https://paiza.io/ja

期待される出力:	
1 2

キャンペーンを行った期間の候補数は1つ 候補日の中で最も早い開始日2日目。

途中経過まとめ

考え方はわかるし、算数で出題されたら即答な問題。

なのにプログラミングになった途端、手が止まるもどかしさ。。。泣

途中経過解答コード:
<?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!!

おわりに

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

なんとか正解までもっていきたい。。。

引き続きランクBになれるよう頑張ります。

※追記※正解できました。

解答コード:
<?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 スキルチェック見本問題(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/

コメントを残す