{ }codelper
文字列の反転文字列の組み立て64ビット整数P0332

編み図を裏側から読む

編み図の一段は、目のまとまりを空白なしでつなげて書いた文字列である。
目のまとまり一つは、目の種類を表す一文字と、そのすぐ後ろにつく個数からなる。
個数は 1 以上の整数で、個数が 1 のときは数字を書かないことも 1 と書くこともある。
たとえば k12p2<y は k が 12 目、p が 2 目、< が 1 目、y が 1 目である。
編んでいるものを返して裏側から見ると、目のまとまりの順番が最後のまとまりから最初のまとまりへと逆になる。
また裏側からは k は p に、p は k に、< は > に、> は < に見える。
ほかの種類はそのまま見える。
一行目に段の数 n、続く n 行に段が一つずつ与えられる。
段ごとに、裏側から見た段を整えた形で一行に出力せよ。
整えた形では、隣り合うまとまりの種類が同じなら一つにまとめて個数を足し、隣り合うまとまりの種類がすべて異なるまで繰り返す。
整えた形では、個数が 1 なら数字を書かず、2 以上なら種類の文字のすぐ後ろにカンマなしの数字だけを書く。
k12p2<y を裏側から見ると y>k2p12、k2k3pk1 を裏側から見ると pkp5 である。

入力
1 ≤ n ≤ 20。
一つの段は 1 文字以上 10,000 文字以下で空白を含まない。
種類の文字は英小文字、<、> のいずれかである。
書かれた個数は 1 以上 999,999,999 以下で、0 で始まらず、カンマなしの数字だけで与えられる。
段は必ず種類の文字で始まる
出力
n 行、各行は裏側から見た段を整えた形
例 1 · stdin
3
k12p2<y
k2k3pk1
p
stdout
y>k2p12
pkp5
k
main.py
入力(stdin)

実行すると、これらの行が順に input()・標準入力に渡されます(実行中に入力を求めません)。

$ 準備完了

コードを入力して解くにはパソコンで開いてください。モバイルでは問題と解答を見られます。

ほかの言語では?言語別の解答を見る · 8 言語の解答

文字列を逆にする方法は言語ごとに違います。
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 sys MIRROR = {"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 10000 static 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;}
Craykonmain.cray · 70 行
거울(ch){    選択 (ch)    {        場合 "k":            返す "p";        場合 "p":            返す "k";        場合 "<":            返す ">";        場合 ">":            返す "<";    }    返す ch;} 뒤쪽에서(row){    kinds = [];    counts = [];    digits = "";    // 문자열을 통째로 뒤집어 맨 끝 글자부터 본다    それぞれ (ch の中 row.逆に())    {        もし (ch >= "0" && ch <= "9")        {            // 개수의 숫자도 거꾸로 모인다            digits = digits + ch;            次へ;        }        count = 1;        もし (digits != "")        {            // 숫자만 다시 뒤집어 수로 바꾼다            count = digits.逆に().数に();            digits = "";        }        kind = 거울(ch);        last = kinds.個数 - 1;        もし (last >= 0 && kinds[last] == kind)        {            // 이웃한 같은 코는 합친다            counts[last] = counts[last] + count;        }        でなければ        {            kinds.追加(kind);            counts.追加(count);        }    }    parts = [];    繰り返す (i = 0; i < kinds.個数; i++)    {        もし (counts[i] > 1)        {            parts.追加(kinds[i] + counts[i]);        }        でなければ        {            parts.追加(kinds[i]);        }    }    返す parts.つなぐ("");} n = コンソール.行読み().数に();繰り返す (i = 0; i < n; i++){    コンソール.書く(뒤쪽에서(コンソール.行読み().空白除去()));}