文字列を逆にする方法は言語ごとに違います。 Python s[::-1]、JS・TS [...s].reverse().join("")(文字列には reverse がないので配列に変えます)、Java new StringBuilder(s).reverse()、C# は char[] に変えて Array.Reverse してから new string(a)、C++ std::reverse(s.begin(), s.end())、Craykon s.逆に() で、C にはそういう関数がないので両端の文字を入れ替えるループを書きます。 落とし穴 ① 文字を丸ごと逆にするだけではまとまりが壊れます。 k12p2<y が y<2p21k になり、数字が文字の前に来て 12 が 21 になります。 逆にした文字列では数字が先に、種類の文字が後に出てくるので、数字をためておき、種類の文字に出会ったところで一つのまとまりとして区切ります。 ② そうしてためた数字は逆向きです。 数字だけもう一度逆にすると 12 に戻ります。 そのまま数に変えると 21 になり、100 は 001 なので 1 になります。 ③ 数字のないまとまりは 1 目です。 空の文字列を数に変えると、JS・TS の Number("") はエラーなしで 0 を返し、Python の int("") は ValueError、Java の Long.parseLong("") は NumberFormatException、C# の long.Parse("") は FormatException、C++ の std::stoll("") は std::invalid_argument、Craykon の "".数に() は「数に変えられません」で止まります。 だから先に空の文字列かどうかを調べます。 ④ k と p を replace("k", "p") の次に replace("p", "k") と順番に置き換えると、最初に k から変わった p までまた k になり、全部 k になります。 一文字ずつ見て一度だけ変えます。 ⑤ 逆にしても隣どうしの関係は変わりませんが、入力が k2k3 のように整っていない形のことがあるので、同じ種類が続いたらまとめます。 このとき 1 目と 1 目がまとまると 2 と書く必要があり、数字を省くのは個数が 1 のときだけです。 ⑥ まとめた個数は 21 億を超えることがあります(999,999,999 目のまとまり三つで超えます)。 C・C++ は long long、Java・C# は long に足します。 JS・TS・Craykon の数は 2^53 まで正確で、Python の int はあふれません。
Pythonmain.py · 26 行
import sysMIRROR = {"k": "p", "p": "k", "<": ">", ">": "<"}def from_back(row): kinds, counts = [], [] digits = "" for ch in row[::-1]: # 문자열을 통째로 뒤집어 맨 끝 글자부터 본다 if ch.isdigit(): digits += ch # 개수의 숫자도 거꾸로 모인다 continue count = int(digits[::-1]) if digits else 1 # 숫자만 다시 뒤집어 수로 바꾼다 digits = "" kind = MIRROR.get(ch, ch) # 한 글자씩 한 번만 바꾼다 if kinds and kinds[-1] == kind: counts[-1] += count # 이웃한 같은 코는 합친다 else: kinds.append(kind) counts.append(count) return "".join(k + (str(c) if c > 1 else "") for k, c in zip(kinds, counts))lines = sys.stdin.read().split("\n")n = int(lines[0])print("\n".join(from_back(lines[1 + i].strip()) for i in range(n)))
JavaScriptmain.js · 31 行
const lines = require("fs").readFileSync(0, "utf8").split("\n");const n = Number(lines[0]);const MIRROR = { k: "p", p: "k", "<": ">", ">": "<" };function fromBack(row) { const kinds = []; const counts = []; let digits = ""; // 문자열에는 reverse가 없어서 글자 배열로 바꿔 뒤집는다 for (const ch of [...row].reverse().join("")) { if (ch >= "0" && ch <= "9") { digits += ch; // 개수의 숫자도 거꾸로 모인다 continue; } // 숫자만 다시 뒤집어 수로 바꾼다. Number("")는 0이라 따로 1로 둔다 const count = digits === "" ? 1 : Number([...digits].reverse().join("")); digits = ""; const kind = MIRROR[ch] ?? ch; if (kinds.length > 0 && kinds[kinds.length - 1] === kind) { counts[counts.length - 1] += count; // 이웃한 같은 코는 합친다 } else { kinds.push(kind); counts.push(count); } } return kinds.map((k, i) => k + (counts[i] > 1 ? counts[i] : "")).join("");}const out = [];for (let i = 1; i <= n; i++) out.push(fromBack(lines[i].trim()));console.log(out.join("\n"));
TypeScriptmain.ts · 33 行
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const n: number = Number(lines[0]);const MIRROR: Record<string, string> = { k: "p", p: "k", "<": ">", ">": "<" };function fromBack(row: string): string { const kinds: string[] = []; const counts: number[] = []; let digits = ""; // 문자열에는 reverse가 없어서 글자 배열로 바꿔 뒤집는다 for (const ch of [...row].reverse().join("")) { if (ch >= "0" && ch <= "9") { digits += ch; // 개수의 숫자도 거꾸로 모인다 continue; } // 숫자만 다시 뒤집어 수로 바꾼다. Number("")는 0이라 따로 1로 둔다 const count: number = digits === "" ? 1 : Number([...digits].reverse().join("")); digits = ""; const kind: string = MIRROR[ch] ?? ch; if (kinds.length > 0 && kinds[kinds.length - 1] === kind) { counts[counts.length - 1] += count; // 이웃한 같은 코는 합친다 } else { kinds.push(kind); counts.push(count); } } return kinds.map((k, i) => k + (counts[i] > 1 ? String(counts[i]) : "")).join("");}const out: string[] = [];for (let i = 1; i <= n; i++) out.push(fromBack(lines[i].trim()));console.log(out.join("\n"));
JavaMain.java · 56 行
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.ArrayList;import java.util.List;public class Main { static char mirror(char ch) { switch (ch) { case 'k': return 'p'; case 'p': return 'k'; case '<': return '>'; case '>': return '<'; default: return ch; } } static String fromBack(String row) { List<Character> kinds = new ArrayList<>(); List<Long> counts = new ArrayList<>(); // 합친 개수는 int를 넘을 수 있다 StringBuilder digits = new StringBuilder(); String back = new StringBuilder(row).reverse().toString(); // 문자열을 통째로 뒤집는다 for (int i = 0; i < back.length(); i++) { char ch = back.charAt(i); if (Character.isDigit(ch)) { digits.append(ch); // 개수의 숫자도 거꾸로 모인다 continue; } // 숫자만 다시 뒤집어 수로 바꾼다 long count = digits.length() == 0 ? 1 : Long.parseLong(digits.reverse().toString()); digits.setLength(0); char kind = mirror(ch); int last = kinds.size() - 1; if (last >= 0 && kinds.get(last) == kind) { counts.set(last, counts.get(last) + count); // 이웃한 같은 코는 합친다 } else { kinds.add(kind); counts.add(count); } } StringBuilder out = new StringBuilder(); for (int i = 0; i < kinds.size(); i++) { out.append(kinds.get(i)); if (counts.get(i) > 1) out.append(counts.get(i)); } return out.toString(); } public static void main(String[] args) throws IOException { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); int n = Integer.parseInt(in.readLine().trim()); StringBuilder out = new StringBuilder(); for (int i = 0; i < n; i++) out.append(fromBack(in.readLine().trim())).append('\n'); System.out.print(out); }}
C#Main.cs · 66 行
using System;using System.Collections.Generic;using System.Text;class Program{ static char Mirror(char ch) => ch switch { 'k' => 'p', 'p' => 'k', '<' => '>', '>' => '<', _ => ch, }; static string Reversed(string s) { char[] a = s.ToCharArray(); // 문자열에는 Reverse가 없어서 char[]로 바꿔 뒤집는다 Array.Reverse(a); return new string(a); } static string FromBack(string row) { var kinds = new List<char>(); var counts = new List<long>(); // 합친 개수는 int를 넘을 수 있다 string digits = ""; foreach (char ch in Reversed(row)) { if (char.IsDigit(ch)) { digits += ch; // 개수의 숫자도 거꾸로 모인다 continue; } // 숫자만 다시 뒤집어 수로 바꾼다 long count = digits == "" ? 1 : long.Parse(Reversed(digits)); digits = ""; char kind = Mirror(ch); int last = kinds.Count - 1; if (last >= 0 && kinds[last] == kind) { counts[last] += count; // 이웃한 같은 코는 합친다 } else { kinds.Add(kind); counts.Add(count); } } var sb = new StringBuilder(); for (int i = 0; i < kinds.Count; i++) { sb.Append(kinds[i]); if (counts[i] > 1) sb.Append(counts[i]); } return sb.ToString(); } static void Main() { int n = int.Parse(Console.ReadLine()); var sb = new StringBuilder(); for (int i = 0; i < n; i++) sb.Append(FromBack(Console.ReadLine().Trim())).Append('\n'); Console.Write(sb); }}
C++main.cpp · 57 行
#include <algorithm>#include <iostream>#include <string>#include <utility>#include <vector>static char mirror(char ch) { switch (ch) { case 'k': return 'p'; case 'p': return 'k'; case '<': return '>'; case '>': return '<'; default: return ch; }}static std::string fromBack(std::string row) { std::vector<std::pair<char, long long>> runs; // 합친 개수는 int를 넘을 수 있다 std::string digits; std::reverse(row.begin(), row.end()); // 문자열을 통째로 뒤집는다 for (char ch : row) { if (ch >= '0' && ch <= '9') { digits += ch; // 개수의 숫자도 거꾸로 모인다 continue; } long long count = 1; if (!digits.empty()) { std::reverse(digits.begin(), digits.end()); // 숫자만 다시 뒤집는다 count = std::stoll(digits); digits.clear(); } char kind = mirror(ch); if (!runs.empty() && runs.back().first == kind) { runs.back().second += count; // 이웃한 같은 코는 합친다 } else { runs.emplace_back(kind, count); } } std::string out; for (const auto& [kind, count] : runs) { out += kind; if (count > 1) out += std::to_string(count); } return out;}int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int n; std::cin >> n; std::string row; for (int i = 0; i < n; i++) { std::cin >> row; std::cout << fromBack(row) << '\n'; }}
Cmain.c · 63 行
#include <stdio.h>#include <string.h>#define MAXLEN 10000static char row[MAXLEN + 2];static char kinds[MAXLEN];static long long counts[MAXLEN]; /* 합친 개수는 int를 넘을 수 있다 */static char mirror(char ch) { switch (ch) { case 'k': return 'p'; case 'p': return 'k'; case '<': return '>'; case '>': return '<'; default: return ch; }}/* C에는 문자열을 뒤집는 함수가 없다: 양 끝 글자를 맞바꾸며 가운데로 온다 */static void reverse(char *s, int len) { for (int l = 0, r = len - 1; l < r; l++, r--) { char t = s[l]; s[l] = s[r]; s[r] = t; }}int main(void) { int n; scanf("%d", &n); for (int line = 0; line < n; line++) { scanf("%10001s", row); int len = (int)strlen(row); reverse(row, len); int m = 0; /* 묶음 수 */ int start = 0; /* 거꾸로 모인 숫자가 시작하는 자리 */ for (int i = 0; i < len; i++) { if (row[i] >= '0' && row[i] <= '9') continue; long long count = 1; if (i > start) { reverse(row + start, i - start); /* 숫자만 다시 뒤집는다 */ count = 0; for (int j = start; j < i; j++) count = count * 10 + (row[j] - '0'); } start = i + 1; char kind = mirror(row[i]); if (m > 0 && kinds[m - 1] == kind) { counts[m - 1] += count; /* 이웃한 같은 코는 합친다 */ } else { kinds[m] = kind; counts[m] = count; m++; } } for (int i = 0; i < m; i++) { putchar(kinds[i]); if (counts[i] > 1) printf("%lld", counts[i]); } putchar('\n'); } return 0;}