<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>レベルアップ問題集 &#8211; FITSブログ</title>
	<atom:link href="http://blog.fits-inc.jp/tag/%E3%83%AC%E3%83%99%E3%83%AB%E3%82%A2%E3%83%83%E3%83%97%E5%95%8F%E9%A1%8C%E9%9B%86/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.fits-inc.jp</link>
	<description>Webシステムの受託開発でお困りなら</description>
	<lastBuildDate>Fri, 19 Jun 2020 10:35:04 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>http://blog.fits-inc.jp/wp-content/uploads/2024/06/cropped-image-5-32x32.png</url>
	<title>レベルアップ問題集 &#8211; FITSブログ</title>
	<link>http://blog.fits-inc.jp</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>じゃんけんの手の出し方 (paizaランク A 相当)をJavaScriptで解きました</title>
		<link>http://blog.fits-inc.jp/2020/02/04/%e3%81%98%e3%82%83%e3%82%93%e3%81%91%e3%82%93%e3%81%ae%e6%89%8b%e3%81%ae%e5%87%ba%e3%81%97%e6%96%b9-paiza%e3%83%a9%e3%83%b3%e3%82%af-a-%e7%9b%b8%e5%bd%93%e3%82%92%e3%81%ae%e3%82%93%e3%81%b3%e3%82%8a/</link>
		
		<dc:creator><![CDATA[FITS Admin]]></dc:creator>
		<pubDate>Tue, 04 Feb 2020 14:00:07 +0000</pubDate>
				<category><![CDATA[技術ブログ]]></category>
		<category><![CDATA[paiza]]></category>
		<category><![CDATA[じゃんけんの手の出し方]]></category>
		<category><![CDATA[レベルアップ問題集]]></category>
		<guid isPermaLink="false">http://blog.fits-inc.jp/?p=337</guid>

					<description><![CDATA[　こちらはコード公開が可能なpaizaのレベルアップ問題集の「じゃんけんの手の出し方」というAランク相当の問題をFITSの代表である藤浦が挑戦した記録です。読み進めるとJavaScript版の解答コードが載っているのでご [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>　こちらはコード公開が可能なpaizaのレベルアップ問題集の「じゃんけんの手の出し方」というAランク相当の問題を<a href="http://www.fits-inc.jp/">FITS</a>の代表である藤浦が挑戦した記録です。読み進めるとJavaScript版の解答コードが載っているのでご注意ください。</p>



<p>問題へのリンクは<a href="https://paiza.jp/works/mondai/skillcheck_sample/janken?language_uid=javascript">こちら</a> </p>



<h2 class="wp-block-heading">問題のルールを読み違えてハマる</h2>



<p>　例題として出ている手が「例えば、あなたが 4 回のじゃんけんで グー、パー、チョキ、グー と出したとすると、出した指の本数の合計は、0 + 5 + 2 + 0 = 7 」となっていて、続く入力のサンプルが</p>



<pre class="wp-block-code"><code>4 7
CGPC</code></pre>



<p>という全勝パターンだったので（引き分けや負けについて言及されてないし、勝った場合の指数のみカウントすればよいのか）と勘違いしました。実務でもそうですが、ソロでのコーディングで思い込みが発生してしまうとリカバリに苦労しますね。</p>



<p>なお、続く入力例2は</p>



<pre class="wp-block-code"><code>5 10
GPCPC</code></pre>



<p>でした。なので普通に考えると5回のじゃんけんで出した指数の合計が10になるのは「パー2回、グー3回」あるいは「チョキ5回」の二通りしかありません。ここで（あいこや負けも考慮した指の数になるのだな）と気づくべきでした。</p>



<p>　ここが思い込みの怖いところで（この問題では、どのような組み合わせで勝っても、勝った際の指数の合計が10になることがない。パーで2回勝つことができない）の後の発想として（本来はGPCPGとするところをGPCPCとしてしまったのかな？）と考えました。この時点で一発クリアの目は消えたのですが、自戒も込めてここからの四苦八苦も記載します。</p>



<h2 class="wp-block-heading">勝ち負けを順列再帰で網羅する？（組み合わせ爆発）</h2>



<p>　N回のじゃんけんに対し、相手の手が固定されているため１回目が価値、2回目が負け・・・N回目が負け、というように勝ち負けの順列のパターン網羅による回答を出そうとしました。その中で全ての手の指数が前提条件と同じものを抽出すれば一応は回答となります。</p>



<p>　（勝ちの場合の指数のみカウントしようと勘違いしているのでこの段階でクリアは出来ないのですが）これは少し考えただけで組み合わせ爆発となる事がわかります。N=1000回であれば再帰で確実にスタックがあふれますし、このアプローチだと解けそうにないことは分かったまま、いったん休憩しました。競技プログラミングでは休憩は敷居が高いですが、業務プログラミングであれば休憩中に回答を思いつくことがままあります。</p>



<h2 class="wp-block-heading">順列ではなく組み合わせの問題であることに気づく</h2>



<p>　少し思考を整理して、そもそも1回目にパーで勝つことと3回目にパーで勝つことを問題の性質上区別する必要はない（どちらも指数+5となるだけ）ため、何回目に何を出したか、という順列の問題ではなく、単純にじゃんけんの総回数N回に対してグーをG回出したとき、かつ、パーをP回出したとき、といった組み合わせの問題であることにようやく気付きました。（ここにいたってもまだ、勝ち手の指の数のみを数えてます）</p>



<p>　この段階で書き上げたコードが下記です。</p>



<pre class="wp-block-code"><code>  // 勝ち手の合計の指数
  &#91;,finger] = lines.shift().split(" ").map(i=>Number(i));
  hands = lines.shift().split("");
  // 勝ち手（相手がチョキなら勝ち手はグー）の最大数をカウント
  gCount = hands.filter(h => h == 'C').length;
  pCount = hands.filter(h => h == 'G').length;
  cCount = hands.filter(h => h == 'P').length;
  win = 0;  
  for (i = 0; i &lt;= pCount; i++) {
      for (k = 0; k &lt;= cCount; k++) {
          if (i * 5 + k * 2 == finger) {
              win = Math.max(win, i + k)
          }
      }
  }
  // グーによる勝ちはそのまま勝利数に加算
  win += gCount;
  console.log(win)</code></pre>



<p>　当然このコードでは、偶然にも解答が全勝時のパターンである入力例1は通過しますが、提出後の問題は1問目から不正解（0点）となりました。</p>



<h2 class="wp-block-heading">paizaの機能で入力をオープンして勘違いに気づく</h2>



<p>　paizaのレベルアップ問題集には、スキルチェックの本番問題にはない機能として、実際の入力値を確かめる機能があります（チケット消費が必要）。そこで入力をオープンしてようやく気付きます。これ、勝ちだけじゃなく「あいこ」も「負け」も指数をカウントしないとダメなやつじゃないか・・・。</p>



<h2 class="wp-block-heading">コードを修正して再提出、100点通過へ</h2>



<p>　これで回答にたどり着くための条件はすべて揃いました。まず、ループはじゃんけんの回数 total 内でグーの回数（G回）、チョキの回数、パーの回数（P回）を網羅できるよう、2次元ループとします（GとPが分かればチョキの回数は求まるため、3次元ではなく2次元ループです）。</p>



<p>　また「あなたは最高で何回じゃんけんに勝つことができるでしょうか」の一文から、指数が同じでも多く勝てる組み合わせがあれば、そちらを採用します。また、グーで何回勝てるか？パーで何回勝てるか？は相手の出した手による制限が掛かります。例えばトータルの指数 finger が10であれば、パーを2回か、チョキを5回出す必要があるのですが、相手がパーを3回しか出してないのであればこのチョキ5回のうち3回までしか勝ちにカウントできません。これはMath.min で（自分がチョキを出した回数、相手がパーを出した回数）の小さいほうを採用することで、相手の手を超えて勝つことを防ぎます。</p>



<p>　グーチョキパーのそれぞれについてこの矛盾しない勝ち数を計算してwinに代入した上で、前回計算した win を上回る場合は win を更新していきます。</p>



<pre class="wp-block-code"><code>  // 合計じゃんけん数、合計の指数
  &#91;total, finger] = lines.shift().split(" ").map(i => Number(i));
  hands = lines.shift().split("");
  // 各手で勝てる最大数をカウント
  gMax = hands.filter(h=>h=='C').length;
  pMax = hands.filter(h=>h=='G').length;
  cMax = hands.filter(h=>h=='P').length;
  win = 0;
  // グーの数とパーの数をループで網羅し、チョキの数はじゃんけん数から導かれる
  for (g = 0; g &lt;= total; g++) {
    for (p = 0; p &lt;= total - g; p++) {
      c = total - g - p;
      if(p * 5 + c * 2 == finger) {
        // 指の数が問題と一致なら、勝ち数の多いほうを採用
        win = Math.max(win, Math.min(g, gMax) + Math.min(p, pMax) + Math.min(c, cMax));
      }
    }
  }
  console.log(win)</code></pre>



<p>　上記のコードで100点となりました。楽しかったです！レベルアップ問題集は、難易度自体は高ランクのものもありますが、期限が切られてないためのんびりと対応できるのが素晴らしいですね。いざとなったら入力そのものを確認できますし、ネットで解説記事も検索することもできるため、高ランク問題を確実に解いて考え方を身に着けたい、という場合には重宝するのではないでしょうか。</p>



<h2 class="wp-block-heading">最後に（宣伝）</h2>



<p>　FITSは仙台にあるシステム開発会社です！社長が趣味でpaizaを解いていたり、役職が全撤廃されているほか、地方のIT会社には珍しくしっかりとしたインセンティブ制度があります。インセンティブ制度により年収ベースで社長を超える社員も居ます。</p>



<p>　また、働きやすさを追求したリモートワーク制度やスーパーフレックス制度も整備されています。自分の実力に対して見合う報酬が支払われていない、柔軟に働けずもやもやしている、という方は、是非FITSでエンジニアとして働いてみませんか？アルバイトも募集しています。</p>



<p>　採用情報は<a href="https://www.fits-inc.jp/%E6%8E%A1%E7%94%A8%E6%83%85%E5%A0%B1/">こちら</a>です。</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>paiza Cランク相当問題「検索履歴」をワンライナ―で解く</title>
		<link>http://blog.fits-inc.jp/2020/02/03/paiza-c%e3%83%a9%e3%83%b3%e3%82%af%e7%9b%b8%e5%bd%93%e5%95%8f%e9%a1%8c%e3%80%8c%e6%a4%9c%e7%b4%a2%e5%b1%a5%e6%ad%b4%e3%80%8d%e3%82%92%e3%83%af%e3%83%b3%e3%83%a9%e3%82%a4%e3%83%8a%e2%80%95%e3%81%a7/</link>
		
		<dc:creator><![CDATA[FITS Admin]]></dc:creator>
		<pubDate>Mon, 03 Feb 2020 13:34:32 +0000</pubDate>
				<category><![CDATA[技術ブログ]]></category>
		<category><![CDATA[paiza]]></category>
		<category><![CDATA[レベルアップ問題集]]></category>
		<category><![CDATA[ワンライナー]]></category>
		<guid isPermaLink="false">http://blog.fits-inc.jp/?p=326</guid>

					<description><![CDATA[※こちらは paiza の中でも解答コードを公開可能なレベルアップ問題集 https://paiza.jp/works/mondai というコーナー内での解答コード掲載です。 paiza にコードの公開可能な「レベルアッ [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>※こちらは paiza の中でも解答コードを公開可能なレベルアップ問題集 <a href="https://paiza.jp/works/mondai">https://paiza.jp/works/mondai</a> <br>というコーナー内での解答コード掲載です。</p>



<p>paiza にコードの公開可能な「レベルアップ問題集」というコーナーがあったので、試しに解いてみることにしました。今回解いたのはCランク相当である「検索履歴」という問題です。</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>検索ワードの履歴とは次のようにつくられます。<br>検索ワード W が以前に入力されたことがある場合：<br>　　履歴中の W を削除する。<br>　　履歴の先頭に W を追加する。<br>検索ワード W が以前に入力されたことがない場合：<br>　　履歴の先頭に W を追加する。 <br>検索ワード W が N 個与えられるので、N 個の検索ワードが与えられた後の履歴を表示するプログラムを書いてください。</p><cite><a href="https://paiza.jp/works/mondai/skillcheck_archive/search_history?language_uid=javascript">https://paiza.jp/works/mondai/skillcheck_archive/search_history?language_uid=javascript</a> </cite></blockquote>



<p>これを、上記の説明文に書かれている処理内容にできるだけ忠実にコーディングすると、このようになると思います。</p>



<pre class="wp-block-code"><code>    // 検索履歴格納用の配列を確保
    history = [];
    lines.slice(1).forEach(word => {
        hit = history.indexOf(word);
        if (hit != -1) {
            // 単語がすでに検索履歴に含まれるなら削除
            history.splice(hit, 1);
        }
        // 検索履歴の先頭に単語を追加
        history.unshift(word);
    });
    // 出力
    console.log(history.join("\n"));</code></pre>



<p>さらに、reduce のアキュムレータ機能を使えば history のようなワーク配列を確保する必要もなくなるので次のように書けます。</p>



<pre class="wp-block-code"><code>    console.log(lines.slice(1).reduce((a, b) => {
        hit = a.indexOf(b);
        if (hit != -1) {
            a.splice(hit, 1);
        }
        a.unshift(b);
        return a;
    }, []).join("\n"));</code></pre>



<p>また、履歴に重複する単語が出てきた際に、一度 unshift したものを、indexOf で存在確認して splice で取り除くのは非効率ですね。なので、unshift する条件を、「重複があった場合は一番最後に登場する単語」＝「現在のインデックス以降のソース配列に含まれない場合」とします。</p>



<pre class="wp-block-code"><code>    console.log(lines.slice(1).reduce((a, b, idx, arr) => {
        // reducer の idx と arr（ソース配列）を利用して
        // 現在のインデックス以降の配列 slice(idx + 1) に対して存在確認
        if (arr.slice(idx + 1).indexOf(b) == -1) {
            a.unshift(b);
        }
        return a;
    }, []).join("\n"));</code></pre>



<p>ここまでくれば、三項演算子や配列のスプレッド構文などを使い、ワンライナーで書けます。※スプレッド構文は巨大な配列を展開するとランタイムエラーとなるので、処理速度の最適化が求められる問題では慎重に使用しましょう</p>



<pre class="wp-block-code"><code>// a.unshift(b) は値を返さないのでスプレッド構文 [b, ...a] で先頭への追加を実現
console.log(lines.slice(1).reduce((a, b, idx, arr) => arr.slice(idx + 1).indexOf(b) == -1 ? [b, ...a] : a, []).join("\n"));</code></pre>



<p>また、ちょっと考え方を変えると、今回の出力は、ほぼ入力配列を reverse したものと言えそうです。ただし、重複があった場合は配列インデックスの大きいほう（後出の方）を残して reverse しなければいけません。これを filter で実現し、ワンライナーで書くと、下記のようなコードになると思います。</p>



<pre class="wp-block-code"><code>console.log(lines.slice(1).filter((l, idx, arr) => arr.slice(idx+1).indexOf(l) == -1).reverse().join("\n"));</code></pre>



<p>ここまでくると可読性が低すぎるということでチーム内レビューでも指摘されると思いますが、考える分には楽しいですね。レベルアップ問題は解答を話し合ったり公開することが認められているので、普通はワンライナーでやらないであろう問題を、チームであーでもないこーでもないと話し合ってワンライナー化してみるのも、三項演算子や reducer への理解が含まるので面白いかもしれません。</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
