题目
leetcode题目:(链接https://leetcode-cn.com/problems/longest-palindrome)。
给定一个包含大写字母和小写字母的字符串,找到通过这些字母构造成的最长的回文串。
在构造过程中,请注意区分大小写。比如 “Aa” 不能当做一个回文字符串。
注意:
假设字符串的长度不会超过 1010。
示例 1:
输入:
"abccccdd"
输出:
7
解释:
我们可以构造的最长的回文串是"dccaccd", 它的长度是 7。
基本思路
这个题和两天之前的“单词拼写”那道题有相似之处,归根到底都是统计字符的数量问题。
我们考虑回文串的特点,在中心点两侧对称位置会有相同的字符,对称中心可以有一个字符也可以没有字符。
所以,如果某字符是偶数个,那么该字符全部数量都将用来构造回文串。如果某字符是奇数个,那么向下取到的偶数个字符都将用来构造回文串,例如有3个 ‘a’ 时,我们可以向下取到2个来构造回文串。
最后,至于对称中心有没有字符,我们就可以通过看有没有某个字符是奇数个即可。
奇数时我们可以用value / 2 * 2来向下取奇数个,当然了,偶数也符合这个公式,所以我们没必要将奇数和偶数分开记数。使用boolean变量来判断是否存在奇数很直接,但更好的我们可以直接使用int型,默认为0,有奇数存在时记为1,最后直接把他加在返回值上更快捷。
优化过程:
- 一开始考虑到哈希表可以很方便地存储键值对,所以使用它来记录,最终代码可以通过,但是耗时很长。
- 由于这个字符种类是确定的,我们可以用数组来代替哈希表,需要注意的是,ASCII码中大小写字母是不连续的,中间有6个其他字符,所以我们需要长度为26 + 26 + 6 = 58的数组,中间6个空间用不到而已。
- 使用数组快了很多,但是没有达到极限速度,不过剩下的都不是很重要的事情了,例如去掉不必要的变量,去掉不必要的数组取值之类的。
具体代码
//Java
class Solution {
public int longestPalindrome(String s) {
int longs = 0;
int hasSingle = 0;
int[] hashArray = new int[58];
for(char c : s.toCharArray()) {
hashArray[c - 65]++;
}
for(int value : hashArray) {
if(value % 2 == 1) {
hasSingle = 1;
}
longs = longs + value / 2 * 2;
}
return longs + hasSingle;
}
}
时间复杂度:遍历了一遍s中的所有字母,所以时间复杂度为
O
(
n
)
O(n)
O(n),n表示s的长度。
空间复杂度:空间复杂度为
O
(
m
)
O(m)
O(m),m表示我们开辟的额外空间,使用数组时我们需要58个,如果使用哈希表,我们就需要52个空间。