Skip to main content

Repeated String Transformation

A character-to-character mapping defines a transformation from a character c1c_1 to a character c2c_2. For example, aba \to b denotes that the character aa should be transformed to the character bb. Note that transformations are directed: aba \to b is different from bab \to a.

A transformation c1c2c_1 \to c_2 can be applied to a string, which results in a new string where all c1c_1s are replaced with c2c_2s. For example, applying the transformation hch \to c to hello world results in cello world.

Given a set of transformations, repeatedly apply them to a string SS until it is no longer possible to apply any more transformations.

For example, if we have two transformations {hc,cb}\{h \to c, c \to b\}, the output for hello world should be bello world: the first h becomes c which then turns into a b.

It is guaranteed that the set of transformations will not contain a cycle, direct or indirect (i.e. {ab,ba}\{a \to b, b \to a\}).

Input Specification

  • The first line will contain an integer TT, denoting the number of transformations.
  • The next TT lines will each contain two lowercase characters c1c_1 and c2c_2, denoting a character-to-character mapping from c1c_1 to c2c_2.
  • The final line will contain a string SS, which is guaranteed to only contain lowercase characters.

Output Specification

Output the result of repeatedly applying the set of transformations to SS.

Examples

Example 1

Input

5
a b
b c
c d
d e
e f
abcdefg

Output

ffffffg

Explanation

The set of transformations looks like a chain, as follows:

abcdefa \to b \to c \to d \to e \to f

It is clear that all of the characters along the chain will be transformed to f. Thus, a, b, c, d, e, and f all become f. The final g is left as is.

Example 2

Input

2
h f
f k
hiss

Output

kiss

Explanation

The hh turns into a ff which then turns into a kk.

Example 3

Input

2
c a
b c
b

Output

a

Example 4

Input

2
a c
b a
bbbb

Output

cccc

Model Solutions

Note: Weak test data caused several unintended solutions (which should not have passed) to get through. (Those who solved the problem at our meeting will get points regardless of the correctness of their solution this week.) We apologize for the confusion!

Solution 1: Brute Force

Intuition

Just do as the problem states: apply each transformation repeatedly in a loop, until none of the transformations have any effect.

Code

t = int(input())
transformations = []
for _ in range(t):
a, b = input().split()
transformations.append((a, b))

s = input()
while True:
changed = False
for a, b in transformations:
replaced = s.replace(a, b)
if s != replaced:
changed = True
s = replaced
if not changed:
break
print(s)

Implementation Details

changed keeps track of whether any transformation has resulted in the string changing in the current iteration. To replace the characters, we use str.replace.

Example

2
h f
f k
hiss
  1. First iteration.
    1. Apply the first transformation, hfh \to f, resulting in fiss.
    2. Apply the second transformation, fkf \to k, resulting in kiss.
    3. As the string changed, the loop continues.
  2. Second iteration.
    1. Apply the first transformation, hfh \to f. No effect.
    2. Apply the second transformation, fkf \to k. No effect.
    3. As the string did not change, break the loop.
  3. Output kiss.

Time Complexity

About O(Ztn)O(|Z|tn) where ZZ is the alphabet. Each iteration of the while loop attempts to apply all tt transformations on the string of length nn. Thus the time complexity of each iteration is O(tn)O(tn).

Moreover, the number of iterations is bounded by the size of the alphabet Z|Z|, given that there are no cycles (indirect or direct) in the set of transformations.

Solution 2: Hash Tables

Intuition

The key insight here is to apply transformations character-by-character rather than on complete strings. That is, to obtain the transformed string for SS, go through each character of SS and find the character that it resolves to rather than transforming all of SS at once.

We can do this with a dictionary that maps a character cc to what character it resolves to. For example, given the following input:

5
a b
b c
c d
d e
e f
abcdefg

We would have the following dictionary:

{
"a": "b",
"b": "c",
"c": "d",
"d": "e",
"e": "f",
}

To look up what a character resolves to, it suffices to look it up in the dictionary repeatedly as long as there is an entry for it. For example, to resolve the character aa, we perform the following steps:

  1. Check if there is an entry for aa.
    1. Yes; so set the current character to bb and continue.
  2. Check if there is an entry for bb.
    1. Yes; so set the current character to cc and continue.
  3. Check if there is an entry for cc.
    1. Yes; so set the current character to dd and continue.
  4. Check if there is an entry for dd.
    1. Yes; so set the current character to ee and continue.
  5. Check if there is an entry for ee.
    1. Yes; so set the current character to ff and continue.
  6. Check if there is an entry for ff.
    1. No; so stop here.

This eventually resolves to ff, which indicates that aa should become ff which is correct.

Code

resolves_to = {}
t = int(input())
for _ in range(t):
a, b = input().split()
resolves_to[a] = b

s = input()
output = []
for c in s:
while c in resolves_to:
c = resolves_to[c]
output.append(c)
print("".join(output))

Time Complexity

O(Zn)O(|Z|n). Consider the following loop:

while c in resolves_to:
c = resolves_to[c]

First, observe that as there are no loops, cc changes each iteration. ZZ is the alphabet, there are Z|Z| possible characters, so resolves_to can have at max Z|Z| keys. In other words, there are only Z|Z| possible values for cc, and as cc's value changes each iteration, the number of iterations is bounded by Z|Z|.

As there are nn iterations where O(Z)O(|Z|) work is being done in each, the overall time complexity is O(Zn)O(|Z|n).