题目地址:
https://leetcode.com/problems/longest-palindrome/
给定一个字符串,可以从其中挑选任意多字符,问能组成的最长回文字符串的长度。
可以先统计字符串中各个字符出现的次数,出现偶数次的全部用上,放在两边,出现奇数次的,取出最多偶数个(如果出现 n n n次并且 n n n是奇数,那就取 n / 2 ∗ 2 n/2*2 n/2∗2个,这里除法是计算机里的整除)。最后看一下是否存在字符出现过奇数次,如果存在,就再挑一个字符摆在中间。代码如下:
import java.util.HashMap;
import java.util.Map;
public class Solution {
public int longestPalindrome(String s) {
if (s == null || s.isEmpty()) {
return 0;
}
Map<Character, Integer> map = new HashMap<>();
for (int i = 0; i < s.length(); i++) {
map.put(s.charAt(i), map.getOrDefault(s.charAt(i), 0) + 1);
}
int res = 0;
boolean odd = false;
// 将出现偶数次的字符出现的次数直接累加到res上去,并且看一下是否存在出现奇数次的字符
for (int num : map.values()) {
res += num / 2 * 2;
if (num % 2 != 0) {
odd = true;
}
}
// 如果存在出现奇数次的字符,则再加1,否则不加
return res + (odd ? 1 : 0);
}
}
时空复杂度 O ( n ) O(n) O(n)。
算法正确性证明:
算法类似贪心法,正确性可以用反证法证明。首先算法里对出现偶数次的字符的对待办法是全拿,如果最优解没有全拿,那可以通过全拿并加在两端的方法构造出一个更长的解,矛盾;其次,对待出现奇数次的字符的方法是拿最大的偶数次,同理这样做也是对的。最后如果有出现奇数次的字符,则随便拿出一个字符摆在正中间即可。