{ }codelper
reversing stringsbuilding strings64-bit integersP0332

Reading a knitting row from the back

One row of a knitting pattern is a string of stitch groups written without spaces. A stitch group is one character for the kind of stitch, followed directly by a count. The count is an integer of at least 1, and when it is 1 the number may be left out or written as 1. For example k12p2<y is 12 stitches of k, 2 of p, 1 of < and 1 of y. When you turn the work and look from the back, the order of the stitch groups is reversed, from the last group to the first. Also, from the back k looks like p, p looks like k, < looks like > and > looks like <.
Other kinds look the same. The first line gives the number of rows n, and each of the next n lines gives one row. For each row print, on one line, the row seen from the back in tidy form. In tidy form, neighboring groups of the same kind are merged into one with their counts added, repeated until all neighboring groups have different kinds. In tidy form a count of 1 is not written, and a count of 2 or more is written as plain digits (no commas) right after the kind character. k12p2<y seen from the back is y>k2p12, and k2k3pk1 seen from the back is pkp5.

Input
1 ≤ n ≤ 20.
A row has from 1 to 10,000 characters and no spaces.
A kind character is a lowercase English letter, < or >.
A written count is from 1 to 999,999,999, does not start with 0, and is given as plain digits without commas.
A row always starts with a kind character
Output
n lines, each the tidy form of the row seen from the back
Example 1 · stdin
3
k12p2<y
k2k3pk1
p
stdout
y>k2p12
pkp5
k
main.py
Input (stdin)

When you run, these lines are fed to input()/stdin in order (the program doesn't stop to ask).

$ Ready

Open this on a computer to write and run code. On mobile you can read the problem and the solutions.

In other languagesShow solutions by language · 8 languages

Each language reverses a string differently: Python s[::-1], JS/TS [...s].reverse().join("") (strings have no reverse, so make an array), Java new StringBuilder(s).reverse(), C# turns it into a char[], calls Array.Reverse, then new string(a), C++ std::reverse(s.begin(), s.end()), Craykon s.Reverse(); C has no such function, so a loop swaps the two end characters.
Trap 1: reversing the characters alone breaks the groups.
k12p2<y becomes y<2p21k: the number moves in front of its letter and 12 turns into 21.
In the reversed string the digits come first and the kind character after them, so collect digits and close a group when you meet the kind character.
Trap 2: the digits collected that way are backward.
Reverse just the digits once more to get 12 back.
Converting them as they are gives 21, and 100 becomes 001, which is 1.
Trap 3: a group without digits is 1 stitch.
Converting an empty string to a number gives 0 without any error in JS/TS (Number("")), a ValueError in Python (int("")), NumberFormatException in Java (Long.parseLong("")), FormatException in C# (long.Parse("")), std::invalid_argument in C++ (std::stoll("")), and Craykon "".ToNumber() stops with 'can't be converted to a number'.
So ask first whether the string is empty.
Trap 4: swapping k and p one after the other, as in replace("k", "p") then replace("p", "k"), turns the p that came from k back into k, so everything becomes k.
Look at one character at a time and change it once.
Trap 5: reversing does not change which groups are neighbors, but the input may be untidy, like k2k3, so groups of the same kind in a row must be merged.
When 1 stitch and 1 stitch merge you must write 2; leave the number out only when the count is 1.
Trap 6: a merged count can pass 2.1 billion (three groups of 999,999,999 are enough).
Add into C/C++ long long or Java/C# long.
Numbers in JS, TS and Craykon are exact up to 2^53, and Python's int never overflows.

Pythonmain.py · 26 lines
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 lines
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 lines
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 lines
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 lines
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 lines
#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 lines
#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 lines
거울(ch){    switch (ch)    {        case "k":            return "p";        case "p":            return "k";        case "<":            return ">";        case ">":            return "<";    }    return ch;} 뒤쪽에서(row){    kinds = [];    counts = [];    digits = "";    // 문자열을 통째로 뒤집어 맨 끝 글자부터 본다    foreach (ch in row.Reverse())    {        if (ch >= "0" && ch <= "9")        {            // 개수의 숫자도 거꾸로 모인다            digits = digits + ch;            continue;        }        count = 1;        if (digits != "")        {            // 숫자만 다시 뒤집어 수로 바꾼다            count = digits.Reverse().ToNumber();            digits = "";        }        kind = 거울(ch);        last = kinds.Count - 1;        if (last >= 0 && kinds[last] == kind)        {            // 이웃한 같은 코는 합친다            counts[last] = counts[last] + count;        }        else        {            kinds.Add(kind);            counts.Add(count);        }    }    parts = [];    for (i = 0; i < kinds.Count; i++)    {        if (counts[i] > 1)        {            parts.Add(kinds[i] + counts[i]);        }        else        {            parts.Add(kinds[i]);        }    }    return parts.Join("");} n = Console.ReadLine().ToNumber();for (i = 0; i < n; i++){    Console.WriteLine(뒤쪽에서(Console.ReadLine().Trim()));}