题目
给定一个包含大写字母和小写字母的字符串 s ,返回通过这些字母构造成的最长的回文串。
在构造过程中,请注意 区分大小写 。比如 "Aa" 不能当做一个回文字符串。
示例1:
输入:s = "abccccdd" 输出:7 解释: 我们可以构造的最长的回文串是"dccaccd", 它的长度是 7。
示例2:
输入:s = "a" 输出:1
示例3:
输入:s = "aaaaaccc" 输出:7
提示:
1 <= s.length <= 2000
s
只由小写 和/或 大写英文字母组成
解题思路
根据题目我们发现,构成回文串的字符对称地分布在字符串两端,因此可以确定如果某字符有偶数个,则其均可以参与构成回文串;而若某字符有奇数个,则只有一组奇数个字符是可以全部参与构成回文串的(多的那个放中间),而剩余的几组都要去掉一个字符。
法1:(执行时间36ms,内存消耗12.9MB)
首先想到的是遍历字符串,统计字符串中每个字符的个数,若该字符的个数为偶数,则直接按该字符的个数记;否则按该字符的个数-1记,同时记录字符个数为奇数的有几个。在遍历过程中,将统计过的字符去掉(可用replace()函数进行替换)。遍历完成后,当奇数个字符的个数大于等于1时,总数加一。
class Solution(object):
def longestPalindrome(self, s):
"""
:type s: str
:rtype: int
"""
sum = 0
q_num = 0
for i in s:
num = s.count(i)
if num % 2 == 0:
sum += num
else:
sum += num-1
q_num +=1
s=s.replace(i,'')
if q_num >= 1:
sum += 1
return sum
法2:(执行时间:20ms,内存消耗12.8MB)
该方法利用collections.Counter(s)来统计某序列中每个元素出现的次数,并以键值对的方式存在字典中。但类型其实是Counter。
nums = [1, 2, 3, 1, 2, 1]
counts = collections.Counter(nums)
print(counts)
## Counter({1: 3, 2: 2, 3: 1})
首先统计序列每个元素出现的次数,然后遍历其values值,针对每个字符,假设它出现了v次,那么可以使用该字符 v/2*2 次,即在回文串左侧和右侧分别放 v/2 个字符( / 为整数除法,比如‘a’出现了5次,则可以在回文串左右两边各放2个‘a’)。
接着判断如果有任一字符出现的次数v为奇数,即 v%2 == 1,那么可以把这个字符作为回文中心来放置,但需要注意的是,最多只有一个字符可以作为回文串中心。因此可以设置变量ans来存储回文串的长度,在遍历字符时,ans每次增加 v/2*2 ,故ans一直都是偶数,当出现第一个次数为奇数的字符后,将ans增加1,它就变成了奇数,后面再遇到其它奇数次的字符时,就不再改变ans的值了。故判断条件可以设置为 if ans % 2 == 0 and v%2 ==1:ans +=1
class Solution(object):
def longestPalindrome(self, s):
"""
:type s: str
:rtype: int
"""
ans = 0
count = collections.Counter(s)
for v in count.values():
ans += v // 2 * 2
if ans % 2 == 0 and v % 2 == 1:
ans += 1
return ans
法3:(执行时间:16ms,内存消耗:12.7)
用set()来创建一个空的集合,用来记录字符出现的次数(集合有自动去重的功能)。字符相同则相消,最后set留下的是不能相消的,奇数次数的字符。
如 aabcab, 最后 set 里留下的是 ac。
假如 set 为空,则说明所有的字符都出现偶数次,最长回文肯定就是s的长度。
否则,最长回文就是 s 长度 - set 长度 + 1, 即从set中取一个字符,和剩下的成偶数字符组成一个最长回文。
即 aabb,再加一个 a 或者 c,可构成最长回文。
class Solution(object):
def longestPalindrome(self, s):
"""
:type s: str
:rtype: int
"""
d = set()
for i in s:
if i not in d:
d.add(i)
else:
d.remove(i)
if not d:
return len(s)
else:
return len(s)-len(d)+1