Example 35
最长回文串
题目概述:给定一个包含大写字母和小写字母的字符串s,返回通过这些字母构造成的 最长的回文串。
在构造过程中,请注意 区分大小写 。比如"Aa"不能当做一个回文字符串。
示例 1:
输入:s = "abccccdd"
输出:7
解释:
我们可以构造的最长的回文串是"dccaccd", 它的长度是 7。
示例 2:
输入:s = "a"
输入:1
示例 3:
输入:s = "bb"
输入: 2
解题思路:回文串是一个正着读和反着读都一样的字符串。以回文中心为分界线,对于回文串中左侧的字符 ch,在右侧对称的位置也会出现同样的字符。例如在字符串 "abba" 中,回文中心是 "ab|ba" 中竖线的位置,而在字符串 "abcba" 中,回文中心是 "ab(c)ba" 中的字符 "c" 本身。我们可以发现,在一个回文串中,只有最多一个字符出现了奇数次,其余的字符都出现偶数次。
那么如何通过给定的字符构造一个回文串呢?可以将每个字符使用偶数次,使得它们根据回文中心对称。在这之后,如果有剩余的字符,我们可以再取出一个,作为回文中心。
对于每个字符 ch,假设它出现了 v 次,可以使用该字符 v / 2 * 2 次,在回文串的左侧和右侧分别放置 v / 2 个字符 ch,其中 / 为整数除法。例如若 "a" 出现了 5 次,那么我们可以使用 "a" 的次数为 4,回文串的左右两侧分别放置 2 个 "a"。
如果有任何一个字符 ch 的出现次数 v 为奇数(即 v % 2 == 1),那么可以将这个字符作为回文中心,注意只能最多有一个字符作为回文中心。在代码中,用 ans 存储回文串的长度,由于在遍历字符时,ans 每次会增加 v / 2 * 2,因此 ans 一直为偶数。但在发现了第一个出现次数为奇数的字符后,将 ans 增加 1,这样 ans 变为奇数,在后面发现其它出现奇数次的字符时,就不改变 ans 的值了。
示例代码如下:
public class LongestPalindromeString { /** * 给定一个包含大写字母和小写字母的字符串s,返回通过这些字母构造成的 最长的回文串。 * 在构造过程中,请注意 区分大小写 。比如"Aa"不能当做一个回文字符串。 * 示例 1: * 输入:s = "abccccdd" * 输出:7 * 解释: * 我们可以构造的最长的回文串是"dccaccd", 它的长度是 7。 * 示例 2: * 输入:s = "a" * 输入:1 * 示例 3: * 输入:s = "bb" * 输入: 2 * 来源:力扣(LeetCode) * 链接:https://leetcode.cn/problems/longest-palindrome */ public static void main(String[] args) { LongestPalindromeString lps = new LongestPalindromeString(); System.out.println(lps.longestPalindrome("abccccdd")); // 7 } /** * 官方 * @param s * @return */ public int longestPalindrome(String s) { int[] count = new int[128]; int length = s.length(); for (int i = 0; i < length; ++i) { char c = s.charAt(i); count[c]++; } int ans = 0; for (int v : count) { ans += v / 2 * 2; if (v % 2 == 1 && ans % 2 == 0) { ans++; } } return ans; } }