📜  门|门CS 2010 |问题 33(1)

📅  最后修改于: 2023-12-03 15:28:48.898000             🧑  作者: Mango

题目介绍:门|门CS 2010 |问题 33

此题出自地球科学与技术学院门|门CS 2010:

小明正在研究一种远古的密码系统,他得到了以下加密方式的信息:

  1. 将原文中的字母按照字母表的升序排序。
  2. 然后将排序后的字母串,按照列数从左到右,行数从上到下填充到一个矩阵中(矩阵第一行从左到右依次是第一列的元素,第二行从左到右依次是第二列的元素,以此类推)。
  3. 最后,将矩阵中的元素按照从上到下,从左到右的顺序连成一串字符串,得到加密后的密文。

例如,原文为“CRYPTOGRAPHY”,矩阵的规格为 3 × 4,则加密后的密文为“CYAPORRGTYPH”。

小明已经成功地解密出了一些密文,但他发现这种密码系统的矩阵规格是由发信人任意指定的,并且一个密文可能有很多种矩阵规格,并且里面可能含有很多无用的字符。你能帮助他吗?

实现一个函数 decode(str: str) -> str,用来解密字符串 str 并返回解密后的字符串。其中,str 是一个非空字符串,由大小写字母和其它 ASCII 码组成,其长度不超过 20000。

请您实现 decode 函数。详细说明请参见下面的函数说明。

函数说明:
def decode(str: str) -> str:
    pass

参数说明:

  • str:非空字符串,由大小写字母和其它 ASCII 码组成,其长度不超过 20000,为一个加密后的字符串。

返回值说明:

解密后的原文(仅包含大小写字母)

示例:

示例1:

>>> decode("PTIRGFRRYYYPHCOOEEQLZUJCBTEUJZUFCFFCRWYMNNZGLXHSEHZIBVLGQAEBLCKWJRIELBHLNWWNSVVZMBIEGBKDFXWDRZSRLSOKMI")
'CRYPOTGRAPHY'

示例2:

>>> decode("RTGOICGQPYRYCRXHPTCIHQAOHYOKCZQRUPGATL");
'CRYPTOGRAPHY'
注意:

上面所有的函数返回值和输入参数类型请按照题目要求严格执行。

解题思路

题目要求我们解密一个加密字符串,这个加密字符串包含了很多无用字符,我们需要把这个字符串恢复成原来的字符串。具体的解密方式如题目描述,这里不再赘述。

首先,我们需要找到这个加密字符串所能对应的所有矩阵规格。

假设这个加密字符串中有 n 个合法的字符,可以分为 m 行 k 列进行排列。则由于整个字符串长度为 len,则有:

mk = n
mk <= len

我们可以通过循环,枚举每一个 mk,判断 len 是否为 mk 的整数倍,来获得 m 和 k 的取值:

for i in range(1, len+1):
    if len % i == 0:
        m, k = i, len // i

然后我们再依次从 str 中选取前 mk 个有效字符,组成一个 m 行 k 列的二维矩阵 matrix,并按照题目要求,按列从上到下转换为原文字符:

matrix = [[0] * k for i in range(m)]
for i in range(m):
    for j in range(k):
        matrix[i][j] = str[i*k+j]
s = ''
for j in range(k):
    for i in range(m):
        s += matrix[i][j]

得到 s 后,我们就可以进行比较了,判断其是否为原来的文本。注意,原文的字符是按照字母表的升序排列后转换而来的,所以也需要暴力枚举并比较排序后的文本。

最后,将所有能够成功解密的原文进行比较,输出字母表顺序最早的一项即可。

完整代码实现

def decode(str):
    l = len(str)
    for i in range(1, l+1):
        if l % i == 0:
            m, k = i, l // i
            matrix = [[0] * k for i in range(m)]
            for i in range(m):
                for j in range(k):
                    matrix[i][j] = str[i*k+j]
            s = ''
            for j in range(k):
                for i in range(m):
                    s += matrix[i][j]
            sort_s = sorted(s)
            sort_str = sorted(str)
            if sort_s == sort_str:
                return ''.join(sorted(set(s), key=s.index))