{ }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++){    控制台.输出(뒤쪽에서(控制台.读行().去空白()));}