小田急である広告の前でだけ学生数人がノート出してて何事かと思ったらこの広告が原因だった。解いたらスッキリする答えが出てきて、答え合わせできないけど確実に正解なのが分かった pic.twitter.com/bszZ0QQQJ5
— 電電猫猫|高橋直希@CoeFont (@nya3_neko2) 2022年1月13日
少し前にTwitterでバズってたこの問題をプログラムで解いてみます。 Pythonとかで解いている方がいたのでC#で解いてみます。
並び替えの方針
良い感じに並び替えてくれる便利ライブラリが探せば何かありそうですが、ここは自前で実装してみることにしました。 ただ、そもそも文字列の並び替えってどうするんだっけ…?そんな便利メソッドあったっけ…?ってなったので次のような作戦でやってみました。
- 文字列から1文字取り出す "ABC" => ["A", "BC"]
- 残りの文字列を並び替える "BC" => ["BC", "CB"]
- 並び替えた文字列と最初に取り出した1文字を結合する "A" + ["BC, "CB"] => ["ABC", "ACB"]
まず文字列のアタマからお尻まで文字を1文字ずつ取り出し、残りの文字列と結合してみます。
var source = "GAKKOU"; for (var index = 0; index < source.Length; index++) { var preWord = source[index]; var postWords = source.Remove(index, 1); Console.WriteLine($"{preWord}{postWords}"); }
GAKKOU AGKKOU KGAKOU KGAKOU OGAKKU UGAKKO
とりあえず6パターンできました。1文字取り出した後の残りの文字列についても同じように並び替えていけば上手くいきそうな気がする…。 つまり並べ替え部分をメソッド化して再帰的に実行していけば設問通り360パターンの文字列が出来るはず。
全パターン並び替える
先ほどのプログラムをメソッド化して再帰的に呼び出すようにしました。 並び替えた結果の重複と辞書順の並び替えは少しズルいですがLINQのメソッド(Distinct、OrderBy)でやってしまいました。
staticvoid Main(string[] args) { var source = "GAKKOU"; var results = GetAllSorts(source) .Distinct() .OrderBy(text => text); var count = 0; foreach (var result in results) { count++; Console.WriteLine($"{count}: {result}"); } } static IEnumerable<string> GetAllSorts(string source) { if (source.Length == 1) { yieldreturn source; yieldbreak; } for (var index = 0; index < source.Length; index++) { // 1文字取り出す var preWord = source[index]; var postWords = source.Remove(index, 1); // 残りの文字列を並び変える var postWordsAllSorts = GetAllSorts(postWords); // 取り出した1文字と並び変えた文字列を結合foreach (var sorted in postWordsAllSorts) { yieldreturn $"{preWord}{sorted}"; } } }
実行結果を確認すると、
1: AGKKOU 2: AGKKUO 3: AGKOKU 4: AGKOUK 5: AGKUKO 6: AGKUOK 省略 97: GOAKKU 98: GOAKUK 99: GOAUKK 100: GOKAKU 101: GOKAUK 102: GOKKAU 103: GOKKUA
100番目の文字列は"GOKAKU"でした。受験生へのメッセージが込められた素敵な問題ですね。