算法解析:最长回文串(难度两颗星)

原题链接:https://codeforces.com/contest/1304/problem/B

题目描述

一个回文串拥有如下特征:无论从左向右读,还是从右向左读,其结果都是一样的,比如abccba, eee就是回文串,而abcde, eefe就不是。注意,一个空的字符串也是回文串。
Gildong想出了这样一个问题:对于给定的n个长度为m、内容各不相同字符串,他想把这些字符串中的某些(0个或是所有也是可以的)拼接在一起,以构成一个回文串,要求这个回文串要尽可能长。

测试数据

输入

第一行包括两个数字nm ( 1 ≤ n ≤ 100 , 1 ≤ m ≤ 50 ) (1\le n \le 100, 1\le m \le 50) (1n100,1m50),分别是字符串的个数和字符串的长度。
接下来的n行,每行是一个字符串。
注意,所有的字符串内容各不相同,但拥有相同的长度m

输出

第一行输出构造的回文串长度,第二行输出构造的回文串。
注意,构造出的最长回文串可能不唯一,这种情况下只要输出任一个满足要求的即可。

例:

# Input #1
3 3
tab
one
bat
# Output #1
6
tabbat

# Input #2
4 2
oo
ox
xo
xx
# Output #2
6
oxxxxo

# Input #3
3 5
hello
codef
orces
# Output #3
0

题目解析

因为所有输入字符串拥有相同的长度,所以简化了解题难度。

从回文串的定义中可以想到,一个回文串肯定是以中间的字符为中心两端对称的,那么,如果让我们自己随意构造一个回文串,应该怎么操作?
我想可以这样:先随便取一个字母,比如a,放在字符串的第1个位置和倒数第1个位置,然后再取一个字母比如b,再放到字符串的第2个位置和倒数第2个位置,这样往复下去即可:

a, b .... b, a

上述构造回文数的方法是每次取一个字符,如果每次取两个字符呢?以ab为例,那么就把ab放在字符串的开始,然后把ab的回文串ba放在字符串的末尾;再取两个字符,比如cd,放在ab的后面,cd的回文串dc放在ba的前面,如此往复,同样可以得到一个回文串:

a b, c d .... d c, b a

妥了,现在开始,每次取m个字符,字符的内容就是程序输入的某个候选字符串s,如果s想存在于最终生成的回文串中,需要满足以下任一个条件:

  1. s的回文串存在于候选列表里
  2. s本身是回文串,这样的话s可以放到最终生成的回文串的中心

因为我们想寻找一个最长回文串,所以,s应该优先满足条件1,否则再去满足条件2,而且,满足条件2s只能保留一个。

参考代码

"""
Longest Palindrome
https://codeforces.com/contest/1304/problem/B
"""
import sys


def get_palindrome(s, length):
    reversed_string = ''
    for i in range(0, length):
        reversed_string += s[length-i-1]
    return reversed_string


def solve():
    string_number = None
    string_length = None
    strings = set()

    # read input
    left_strings = None
    for line in sys.stdin:
        if string_number is None:
            ns = line.split()
            string_number = int(ns[0])
            string_length = int(ns[1])
            left_strings = string_number
        else:
            strings.add(line.strip())
            left_strings -= 1
            if left_strings == 0:
                break

    # construct palindrome
    palindrome_head = ''
    palindrome_tail = ''
    palindrome_pendding = None

    used_string = set()
    for s in strings:
        if s in used_string:
            continue

        palindrome_s = get_palindrome(s, string_length)
        if s == palindrome_s:
            palindrome_pendding = s
        elif palindrome_s in strings:
            palindrome_head += s
            palindrome_tail = palindrome_s + palindrome_tail
            used_string.add(palindrome_s)

    result_string = palindrome_head
    if palindrome_pendding is not None:
        result_string += palindrome_pendding
    result_string += palindrome_tail

    print(len(result_string))
    print(result_string)


if __name__ == '__main__':
    solve()
   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值