Javascriptで競技プログラミングに参加してみた2

date_range 2022/11/22
GUARDIAN Creative BLOG
ダウンロード

前回の記事の続きです。


さて前回の記事にて書いた通り、アルゴリズム初心者のワタシがLeetcodeのプログラミングコンテストに参加したところ

4問中最も易しいEasyの1問しか解けず残りは問題文の意味を理解することで精一杯だったというのが前回までのあらすじです(´・ω・`)


下記がそのときのコンテストにおけるNormalレベル問題です。

2466. Count Ways To Build Good Strings

Integer型のzero, one, low,highが与えられた時、空の文字列から始まり以下のステップで文字列を構成していきます。
文字'0'をzero回追加する。
文字'1'をone回追加する。
これらの手順は何度でも行うことができるものとします。
上記の処理によって作られた文字列のうち、長さがlowからhighの間のものを「良い文字列」と呼ぶものとします。
これらの性質を満たす良い文字列を何通り作ることができるかを、返り値として返しなさい。ただし答えがとても大きくなる可能性があるので、その量を1000000007 で割ったあまりを求めること。



Example 1:

Input: low = 3, high = 3, zero = 1, one = 1
Output: 8
Explanation: 
条件を満たす文字列のひとつとして "011" があります。 
これは次のように構成することができます。 : "" -> "0" -> "01" -> "011". 
この例では、二進数の"000"から"111"までのすべての値が「良い文字列」となります。

Example 2:

Input: low = 2, high = 3, zero = 1, one = 2
Output: 5
Explanation: 「良い文字列」は "00", "11", "000", "110", 及び "011" です。

(いずれも筆者訳)



( °᷄д°᷅) ・・・


(つд⊂)ゴシゴシ


(;゚Д゚)…?!


ナニイッテルカワカラナイ・・・


問題文の意味をなんとか読み解こうと色々調べた結果、腹落ちするまで45分もの時間がかかってしまいました(^^;


そんなこんなで問題文を読み解こうと四苦八苦しているうちに、どうやら「ただし答えがとても大きくなる可能性があるので、その量を1000000007 で割ったあまりを求めよ。」という部分は競技プログラミングお決まりの文句のようだと気づきました。


このあたり、競プロ特有の言い回しや発想の仕方があるため、慣れるにはとにかくひたすら問題を解く練習をする必要がありそうです。


幸いLeetcodeには過去のコンテストの問題や、カリキュラムが豊富にあるので解く問題には困りません。

回答例

コンテスト終了後、他の参加者の方々のコードを見るとだいだい以下のような感じで解かれているものが多かったです。


var countGoodStrings = function(low, high, zero, one) {
  let answer = 0;
  const dp = Array(high + 1).fill(0);
  dp[0] = 1;
  for(let i = 1; i <= high; i++) {
    if(i >= zero) {
      dp[i] += dp[i - zero];
    }
    if( i >= one) {
      dp[i] += dp[i - one];
    }
    dp[i] %= 10**9 + 7;
    if(i >= low) {
      answer = (answer + dp[i]) % (10**9 + 7);
    }

  }  
  return answer;    
};


dpという変数を使っている人が多かったのでなんか意味があるのかな?と思い調べたところ

Dynamic Programming、動的計画法という名前の有名なアルゴリズムだそう。


どうやら競プロ界ではとてもメジャーなアルゴリズムらしく、これを覚えるだけでもずいぶん解ける問題が増えそうです。

とはいえこのアルゴリズムにもたくさんの種類があるようで、一通り学んで身に着けるためにもある程度回数を重ねる必要がありそうです。

所感

そんなこんなであっという間に時間切れで終わってしまった初めてのプログラミングコンテストでした💦

5営業日以内に詳しい結果が算出される、とあり、じきに成績が通知されました。

レートは1441、グローバルランキングは225,736/339,893、上位67.1%だそうです( ;∀;)


これはもう慣れしかないので、継続してチャレンジしてレートを上げていきたいですね!


ところで面白いなと思ったのが、「いい文字列」かどうかは無視して総当たりで文字列を書き出していくと下記のようになり、

さらに先頭に1をつけると、まんま二進数の数になりました。


逆にいうと1から始めて、一番大きい桁の数を差し引くと


0,01,0123,01234567……


と2^nだけ数字を繰り返していくことになります。

文字列としてではなく、数列的に問題を解くこともできそうで、ちょっと興味深いな〜と感じました!

また調べて解決法が分かりましたら記事を更新いたします!

人物

マーケティング部 クリエイティブプロダクト隊 クォリティコントロール班 班長

松村 晶(まつむら あき)


HTMLとCSSから始まり、Web関連の記事など広く更新していきます。

毎週2回(月・金予定)に欠かさず更新(できたらいいなと思っている)


今回使用した技術:Javascript