{ }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()·표준 입력으로 들어가요(실행 중에 묻지 않아요).

$ 준비됐어요

코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.

다른 언어로는?언어별 풀이 보기 · 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()), 크레이콘 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, 크레이콘 "".수로변환()은 '수로 바꿀 수 없어요'로 멈춰요.
그래서 빈 문자열인지 먼저 물어요.
④ 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·크레이콘의 수는 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++){    콘솔.쓰기(뒤쪽에서(콘솔.줄읽기().공백제거()));}