String Transformation 1 (Codeforces 1383A)
Tags: Greedy, dsu

Note that the only difference between String Transformation 1 and String Transformation 2 is in the move Koa does. In this version the letter $$$y$$$ Koa selects must be strictly greater alphabetically than $$$x$$$ (read statement for better understanding). You can make hacks in these problems independently.Koa the Koala has two strings $$$A$$$ and $$$B$$$ of the same length $$$n$$$ ($$$|A|=|B|=n$$$) consisting of the first $$$20$$$ lowercase English alphabet letters (ie. from a to t).In one move Koa:  selects some subset of positions $$$p_1, p_2, \ldots, p_k$$$ ($$$k \ge 1; 1 \le p_i \le n; p_i \neq p_j$$$ if $$$i \neq j$$$) of $$$A$$$ such that $$$A_{p_1} = A_{p_2} = \ldots = A_{p_k} = x$$$ (ie. all letters on this positions are equal to some letter $$$x$$$).  selects a letter $$$y$$$ (from the first $$$20$$$ lowercase letters in English alphabet) such that $$$y>x$$$ (ie. letter $$$y$$$ is strictly greater alphabetically than $$$x$$$).  sets each letter in positions $$$p_1, p_2, \ldots, p_k$$$ to letter $$$y$$$. More formally: for each $$$i$$$ ($$$1 \le i \le k$$$) Koa sets $$$A_{p_i} = y$$$. Note that you can only modify letters in string $$$A$$$.Koa wants to know the smallest number of moves she has to do to make strings equal to each other ($$$A = B$$$) or to determine that there is no way to make them equal. Help her!

Input: Each test contains multiple test cases. The first line contains $$$t$$$ ($$$1 \le t \le 10$$$) — the number of test cases. Description of the test cases follows.The first line of each test case contains one integer $$$n$$$ ($$$1 \le n \le 10^5$$$) — the length of strings $$$A$$$ and $$$B$$$.The second line of each test case contains string $$$A$$$ ($$$|A|=n$$$).The third line of each test case contains string $$$B$$$ ($$$|B|=n$$$).Both strings consists of the first $$$20$$$ lowercase English alphabet letters (ie. from a to t).It is guaranteed that the sum of $$$n$$$ over all test cases does not exceed $$$10^5$$$.

Output: For each test case:Print on a single line the smallest number of moves she has to do to make strings equal to each other ($$$A = B$$$) or $$$-1$$$ if there is no way to make them equal.

Note:   In the $$$1$$$-st test case Koa:   selects positions $$$1$$$ and $$$2$$$ and sets $$$A_1 = A_2 = $$$ b ($$$\color{red}{aa}b \rightarrow \color{blue}{bb}b$$$).  selects positions $$$2$$$ and $$$3$$$ and sets $$$A_2 = A_3 = $$$ c ($$$b\color{red}{bb} \rightarrow b\color{blue}{cc}$$$).   In the $$$2$$$-nd test case Koa has no way to make string $$$A$$$ equal $$$B$$$.  In the $$$3$$$-rd test case Koa:   selects position $$$1$$$ and sets $$$A_1 = $$$ t ($$$\color{red}{a}bc \rightarrow \color{blue}{t}bc$$$).  selects position $$$2$$$ and sets $$$A_2 = $$$ s ($$$t\color{red}{b}c \rightarrow t\color{blue}{s}c$$$).  selects position $$$3$$$ and sets $$$A_3 = $$$ r ($$$ts\color{red}{c} \rightarrow ts\color{blue}{r}$$$).  

Sample Inputs:
5
3
aab
bcc
4
cabc
abcb
3
abc
tsr
4
aabd
cccd
5
abcbd
bcdda

Sample Outputs:
2
-1
3
2
-1

Solution (Python):
import collections

def compare(n, a, b):
    for i in range(n):
        if a[i] < b[i]:
            connects[a[i]].add(b[i])
        if a[i] > b[i]:
            print(-1)
            return 1
    return 0
for _ in range(int(input())):
    n = int(input())
    a = str(input())
    b = str(input())
    connects = collections.defaultdict(set)
    if compare(n, a, b):
        continue
    ans = 0
    change = sorted(connects, reverse=True)
    for i in range(len(change)):
        ans += len(connects[change[i]])
        for j in change[i + 1:]:
            if connects[j] & connects[change[i]]:
                connects[j] -= connects[change[i]]
                connects[j].add(change[i])
    print(ans)

Solution (Python):
def dfs(u):
    V[u] = 0
    return sum((dfs(v) for v in g[u] if V[v])) + 1
I = input
for _ in [0] * int(I()):
    I()
    V = [1] * 117
    g = [[] for _ in V]
    f = 0
    for (x, y) in zip(map(ord, I()), map(ord, I())):
        f |= x > y
        g[x] += (y,)
        g[y] += (x,)
    print((sum((dfs(i) - 1 for i in range(117) if V[i])), -1)[f])

Solution (Python):
line_init = int(input())

def recur(dic, key):
    if not mark[key]:
        mark[key] = True
        if key in dic.keys() and dic[key]:
            for h in dic[key]:
                recur(dic, h)
    return 0
for i in range(line_init):
    line_1 = int(input())
    line_2 = input()
    line_3 = input()
    world = set(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't'])
    dic = {x: set() for x in world}
    count = 0
    for i in range(line_1):
        if line_2[i] > line_3[i]:
            count = -1
            break
        if line_2[i] != line_3[i]:
            dic[line_2[i]].add(line_3[i])
            dic[line_3[i]].add(line_2[i])
    if count != -1:
        alf = list(world)
        alf.sort()
        mark = dict.fromkeys(alf, False)
        count = 20
        for i in range(len(alf)):
            if not mark[alf[i]]:
                count -= 1
                recur(dic, alf[i])
    print(count)