https://leetcode-cn.com/problems/longest-palindrome/
并不需要去构造一个回文串,只需要返回长度即可
思考了一下,找了个规律:
- 如果当前字符个数总和是偶数,则不能存在任何字符的个数是奇数
- 如果当前字符个数总和是奇数,则只能存在一个奇数
那么我们先建一个字典,然后遍历字典
- 统计字符数总和
- 统计字符数是奇数的字符
- 统计字符数是奇数的字符个数
遍历一遍之后,判断上面两条规律是否满足,只要满足其中一条,那么当前肯定是最大回文串
如果不满足,无论如何都要减去一个是奇数的字符个数,因为奇数-1之后,肯定就是偶数了,接着重新遍历即可(总会把所有奇数变成偶数)
一开始我想的是减少那个最小的key,但是好像不对
例如a=2,b=2,c=3,d=1的情况,如果直接减去c=3的话,那么就成立了,如果减去d=1的话,那么就还是不成立,就错过最大回文子串了
所以只需要减去第一个是奇数的字符就行了
class Solution:
def longestPalindrome(self, s: str) -> int:
#不需要真的组成一个串
#总长度为偶数的回文串,每个元素必须都是偶数
#总长度为奇数的回文串,最多一个元素是奇数,其余都是偶数
#直接从最长的长度判断
#如果可以满足以上两个条件,则成功
#减去一个key为奇数的值
dct = dict()
for ch in s:
dct[ch] = dct.get(ch, 0) + 1
while True:
size = 0
oddnum = 0
oddnumLst=[]
flag = True
for i, j in dct.items():
size += j
if j % 2 != 0:
oddnum += 1
oddnumLst.append(i)
if size % 2 == 0: # 是偶数长度,不能有偶数
if oddnum > 0: # 如果出现奇数
flag = False
elif size % 2 != 0: # 是奇数长度,只能有一个奇数
if oddnum != 1:
flag = False
if flag:
return size
else:
# 减少第一个奇数个数
dct[oddnumLst[0]]-=1
if dct[oddnumLst[0]] == 0:
del dct[oddnumLst[0]]
后面看了一下提交记录,发现一年前自己已经做过了
class Solution {
public:
int longestPalindrome(string s) {
int mp[52]={0};
for(char ch:s){
if(ch<='z'&&ch>='a')
mp[ch-'a']++;
else
mp[ch-'A'+26]++;
}
int ans=0;
int odd=0;
for(int i=0;i<52;i++){
ans+=mp[i];
if(mp[i]%2!=0)
odd++;
}
if(odd!=0) ans-=odd-1;
return ans;
}
};
思路是这样的,也是统计总个数,然后再统计出现个数是奇数的字符个数
假如有max个字符是奇数,我们只能留一个奇数来构成回文字符串,而把一个奇数变为偶数需要减1
所以最终的答案要减去max-1个1
贴一下别人比较好理解的代码
java
class Solution {
public int longestPalindrome(String s) {
int[] cnt = new int[58];
for (char c : s.toCharArray()) {
cnt[c - 'A'] += 1;
}
int ans = 0;
for (int x: cnt) {
// 字符出现的次数最多用偶数次。
ans += x - (x & 1);
}
// 如果最终的长度小于原字符串的长度,说明里面某个字符出现了奇数次,那么那个字符可以放在回文串的中间,所以额外再加一。
return ans < s.length() ? ans + 1 : ans;
}
}
https://leetcode-cn.com/problems/longest-palindrome/solution/javade-2chong-shi-xian-fang-fa-by-sweetiee/