将字符按照原有几个字符串的排列规律组和成一个新的字符串

这个问题是在https://py.checkio.org/上面的一道题原题我放在下面.

The Robots have found an encrypted message. We cannot decrypt it at the moment, but we can take the first steps towards doing so. You have a set of "words", all in lower case, and each word contains symbols in "alphabetical order". (it's not your typical alphabetical order, but a new and different order.) We need to determine the order of the symbols from each "word" and create a single "word" with all of these symbols, placing them in the new alphabetial order. In some cases, if we cannot determine the order for several symbols, you should use the traditional latin alphabetical order. For example: Given words "acb", "bd", "zwa". As we can see "z" and "w" must be before "a" and "d" after "b". So the result is "zwacbd".

Input: Words as a list of strings.

Output: The order as a string.

Example:

 

How it is used: This concept can be useful for the cryptology, helping you to find regularities and patterns in natural text and ciphered messages.

Precondition: For each test, there can be the only one solution.
0 < |words| < 10

大概意思我说一下.首先我们会获得几个字母组合,根据这些组合的排列规律重新排列成一组新的字母组合.如果其中存在没有联系的字母,就按照字母表顺序进行排序.比如说"acb", "bd", "zwa".这组,从"acb", "zwa"这个两个就可以得出字母'a'是在最中间.得到新组合'zwacb',再结合"bd".得出最终的组合'zwacbd'

其实最一开始自己做感觉挺简单的,也很容易作对.但是当想转换为计算机语言的时候就想不太明白了.有些我们认为理所当然的结论但是自己怎么也理解不了其中的推理过程让我自己非常的苦恼.

最终自己想出了一个笨办法.首先把所有字母都提取出来.然后寻找出在这个前后一个的全部字母,然后存在一个表里面,形成约束条件的标.原计划是整个迭代一遍,先找插入前面的,再插入后面的.如果插入的时候发现之前已经插入过了就先删了原来的再插入.结果显示只需要向前或者向后插入一遍就可以得到结果了.具体细节可以看我代码中的注释

import re

def remove_key_letter(key , lis):
    '''
    移除正则后多余的当前字母输入例如lis=[av, ab, a],key=a,输出[v, b]
    '''
    lis_=[]
    for i in lis :
        if key in i :
            i = i.replace(key,'')
            if i =='':
                continue
            lis_.append(i)
    return  lis_


def find_context(data):
    '''
    创建所有字母的集合后,使用正则表达式寻找每个字母前后所包含的字母
    创建一个数据形式[ 当前字母, [前面包含的字母列表], [后面包含的字母列表]]
    返回字母集合key_letter,以及数据列表key_table
    '''
    key_letter=''
    for i in data:
        key_letter += i
    # 按照字母顺序排一下
    key_letter=sorted(list(set(key_letter)),reverse=False)

    key_table = []
    for i in key_letter:
        front=[]
        back = []
        for j in data:
            #需要这样写正则表达式'{}[^{}]?'.format(i, i).不然无法匹配例如'aaz'中的az,只能匹配上aa
            for m in remove_key_letter(i ,re.findall('[^{}]?{}'.format(i, i), j)):
                if m != None:
                    front.append(m)
            for n in remove_key_letter(i ,re.findall('{}[^{}]?'.format(i, i), j)):
                if n != None:
                    back.append(n)
        # 去除一下重复的值加快运算
        key_table.append([i, list(set(front)), list(set(back))])
    # print(key_table)
    return key_table, key_letter


def find_inder(key, id ,key_table:list , key_letter:list ,end_text=[]):
    '''
    使用递归函数寻找关键函数前后(由id决定1是向前找2是向后找)所有字母,一直找到最前或
    最后停止.
    :param key: 字母
    :param id: 向前还是向后
    :param key_table: 所有字母前后包含的字母数据列表key_table
    :param key_letter: 字母集合
    :param end_text: 添加一个返回值供递归函数之间传递数据.
                    注意!!!!这里调用的时候需要传入初始值[]不然会把上次的结果带入下一次
    :return: 关键字母前后的字母,含有重复值
    '''

    end_text.append(key)
    if key_table[key_letter.index(key)][id] == []:
        pass
    else:
        for i in key_table[key_letter.index(key)][id]:
            # END_TEXT.append(i)
            find_inder(i, id, key_table, key_letter, end_text)

    return end_text


def checkio(data):
    key_table, key_letter = find_context(data)
    end_text = []


    for m in key_letter:
    # 向前插入法,需要在字母表key_letter排序的时候反向排序
    # 才能在不确定的时候按照字母表顺序进行排列输出正确结果
    # 向前向后都行,进行一次就可以出正确结果了
        x = find_inder(m, 1, key_table, key_letter,[])
        for i in range(len(x)):
            if x[i] in end_text:
                end_text.remove(x[i])
                end_text.insert(0, x[i])
            else:
                end_text.insert(0, x[i])
    # # print('向前之后的结果',''.join(end_text))


    # 向前插入法,需要在字母表key_letter排序的时候正向排序
    # 才能在不确定的时候按照字母表顺序进行排列输出正确结果
    # 向前向后都行,进行一次就可以出正确结果了
    for m in key_letter:
        x = find_inder(m, 2, key_table, key_letter,[])

        for i in range(len(x)):
            if x[i] in end_text:
                end_text.remove(x[i])
                end_text.append(x[i])
            else:
                end_text.append(x[i])
    # print('向后插入一遍最终输出',"".join(end_text))

    return "".join(end_text)

#These "asserts" using only for self-checking and not necessary for auto-testing
if __name__ == '__main__':
    print(checkio(["jhgedba","jihcba","jigfdca"]))

    assert checkio(["jhgedba","jihcba","jigfdca"]) == "jihgefdcba"

    assert checkio(["acb", "bd", "zwa"]) == "zwacbd", \
        "Just concatenate it"
    assert checkio(["klm", "kadl", "lsm"]) == "kadlsm", \
        "Paste in"
    assert checkio(["a", "b", "c"]) == "abc", \
        "Cant determine the order - use english alphabet"
    assert checkio(["aazzss"]) == "azs", \
        "Each symbol only once"
    assert checkio(["dfg", "frt", "tyg"]) == "dfrtyg", \
        "Concatenate and paste in"

提交正确了以后发现有其他人做的比较简单的方法我也贴在下面供大家参考.

import re
def checkio(data):
    result = ''
    while(len(''.join(data))):
        print('\'\'.joindata====',''.join(data))
        # heads = {word[0] for word in data if len(word) > 0}
        # 上面是之前别人写的一行解决,我给转换成比较好读的形式放在下面了 
        # 获取全每个组合第一个字母
        heads = []
        for word in data:
            if len(word) > 0:
                heads.append(word[0])
        heads = list(set(heads))
        
        # leftends = sorted(h for h in heads if sum(word.index(h) if h in word else 0 for word in data) == 0)
        # 上面是之前别人写的一行解决,我给转换成比较好读的形式放在下面了 
        # 判断这些第一个字母究竟是不是真正的第一个
        leftends =[]
        for h in heads:
            su =[]
            # 获得每个字母的位置如果位置的和大于一就不是第一个
            for word in data:
                if h in word:
                    su.append(word.index(h))
                else:
                   su.append(0)
            if sum(su)==0:
                leftends.append(h)
        # 如果有多个可能是第一个的就按照字母表排序
        leftends = sorted(leftends)
        # 取排序后的第一个
        result += leftends[0]
        # 把查如结果的字母从原数据中删除
        data = [re.sub(leftends[0], '', word) for word in data]
        print(f'heads={heads} leftends={leftends} result={result} data={data}')
    return result

 

 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值