UWSCでエンジニアならば1時間以内に解けなければいけない問題をチートして解く
問4と問5を解答例を見て解いてみました。
問4は、解答例にヒントないのね。
問5の解答例は素晴らしい。
問4と5の関数
問題等や他の解答は、
UWSCでエンジニアならば1時間以内に解けなければいけない問題を解く - じゅんじゅんのきまぐれ
を参考にしてください。(リンク先の問4の解答にはバグがあるのは秘密です)
どちらも、リンク先と比べて数倍早いです。はい。
FUNCTION Q4F(q[]) RESULT = "" DIM i, in, s, f, m, p, b, c, j, pb FOR i = 0 TO LENGTH(q) - 1 in = i s = 1 f = TRUE m = LENGTH(q) - 1 p = "" WHILE f c = COPY(q[i] + p, s, 1) FOR j = i + 1 TO m b = LENGTH(q[j]) IFB s <= b THEN pb = COPY(q[j], s, 1) f = TRUE ELSE pb = COPY(p, s - b, 1) ENDIF IFB pb >= c THEN IFB pb = c THEN in = in + 1 ELSE in = i c = pb f = FALSE ENDIF b = q[j] q[j] = q[in] q[in] = b ENDIF NEXT IF in <> i THEN p = p + c m = in in = i s = s + 1 ELSE f = FALSE ENDIF WEND RESULT = RESULT + q[i] NEXT FEND FUNCTION Q5F() DIM a[] = 1,2,3,4,5,6,7,8,9 RESULT = Q5FSub(100, a[0], a, 1) FEND FUNCTION Q5FSub(sum, num, arr[], index) // 末端判定 IFB index < LENGTH(arr) THEN // 足し算 DIM i, resAdd = Q5FSub(sum - num, arr[index], arr, index + 1) FOR i = 0 TO LENGTH(resAdd) - 1 resAdd[i] = num + "+" + resAdd[i] NEXT // 引き算 DIM resSub = Q5FSub(sum - num, -arr[index], arr, index + 1) FOR i = 0 TO LENGTH(resSub) - 1 resSub[i] = num + "" + resSub[i] NEXT // 結合 DIM j = num * 10 IF num >= 0 THEN j = j + arr[index] ELSE j = j - arr[index] DIM resMrg = Q5FSub(sum, j, arr, index + 1) // Merge RESULT = SPLIT(JOIN(resAdd) + " " + JOIN(resSub) + " " + JOIN(resMrg), , TRUE) ELSE IFB num = sum THEN RESULT = SAFEARRAY(0, 0) RESULT[0] = sum ELSE RESULT = SAFEARRAY(0, -1) ENDIF ENDIF FEND
問4解説
総当たりに比べるとどうしてもコードが長くなります。
基本思想は、
- 1桁目が最大のものを前に集める
- 1桁目が最大のものが一つなら、それは確定して次を探す
- 1桁目が最大のものが複数なら、1桁目を待避して2桁目が最大のものを集める
- この時、桁数が足りない場合、待避した文字を補完して比較対象を取り出す
- ただし、もし全てで補完した場合は、全て同じ数字ということなので、それは確定して次を探す
- 2桁目が最大のものが一つなら、それは確定して次を探す
- 2桁目が最大のものが複数なら、2桁目も待避して3桁目、、、と繰り返す
そんな感じです。
総当たり版は、数値として大小比較をしていますが、こちらは文字としてしか扱っていないので、桁数制限はありません。
問5解説
この問題、実は素晴らしいですね。
総当たりでEVALするという野蛮行為がいらないとは。
解答例(英語)の解説を読んだ方が良いです。
この解説以上のことは説明できませんし、その解説通りに組んでみました。
これFizzBuzzとあわせて覚えておきたい。
アルゴリズム的力量を測りたくなったら、
- まずはFizzBuzz
- 次に問5。EVAL的なものを使ったなら、使わない方法も考えてみて、と誘導
- 最後に問4
かな。
問5の誘導は、
- 関数をf、数列を1...9と表現したとすると、求める関数は、f(1...9)=100だね。
- 組み合わせるのは、「+」と「-」と「数値結合」
- 「+」を考えると、1+f(2...9)=100。すなわち、f(2...9)=99
- 「-」は、1+f(-2,3...9)=100。すなわち、f(-2,3...9)=99
- 「数値結合」は、f(12,3...9)=100
となるようなfということ。
もう一歩踏み込むと
- f(2...9)=99に対して「+」は、2+f(3...9)=99。f(3...9)=97
- f(2...9)=99に対して「-」は、2+f(-3,4...9)=99。f(-3,4...9)=97
- f(2...9)=99に対して「数値結合」は、f(23,4...9)=99
こんな感じでfの中身がどんどん減っていく。
最終的に、fに渡す数字が一つで求める値と同じであれば、求めるパターン、ということ。
操作は「+」「-」「数値結合」だけなので、f(9)=9といった同じ値でないと、生成できませんから。