文章目录
面试题 01.04. 回文排列
线性枚举+计数
给定一个串,看他能否变成一个回文串。那么我们就来观察回文串的结构,如果回文串的长度是偶数,那么说明他的前半段和后半段是完全相同的,换言之每一个字符在串中出现次数都是偶数(因为一个字符可能在串的半段中就多次出现);如果回文串的长度是奇数,也仅有可能中间一个字符出现的次数是奇数次。所以我们可以按照这个规律对每一个字符出现的次数进行计数
class Solution {
public:
bool canPermutePalindrome(string s) {
unordered_map<char,int>mp;
int one=0;
for(int i=0;i<s.size();i++)
{
mp[s[i]]++;
}
for(auto t:mp)
{
if(t.second%2) one++;
if(one>1) return false;
}
return true;
}
};
剑指 Offer II 018. 有效的回文
双指针
整合一下需要考虑的部分为一个新串,然后用双指针从定义出发来判断是不是回文串
class Solution {
bool check(string ch)
{
int i=0,j=ch.size()-1;
while(i<j)
{
if(ch[i]!=ch[j]) return false;
i++,j--;
}
return true;
}
public:
bool isPalindrome(string s) {
string ch;
for(int i=0;i<s.size();i++)
{
if(s[i]>='A'&&s[i]<='Z') ch+=s[i]+32;
else if(s[i]>='a'&&s[i]<='z') ch+=s[i];
else if(s[i]>='0'&&s[i]<='9') ch+=s[i];
}
return check(ch);
}
};
409. 最长回文串
贪心
根据回文串的定义(第一题中有说明)我们呢总是可以有这样一种贪心策略:对每一个字符计数,只加他的偶数部分。最后如果还有剩余,加上一个字母作为中心回文轴(看了官解除2乘2好妙)
class Solution {
public:
int longestPalindrome(string s) {
unordered_map<char, int> mp;
int ans = 0;
for (char t:s)
mp[t]++;
for (auto t:mp)
{
int v=t.second;
ans+=v/2*2;
if (v%2==1&&ans%2==0)
ans++;
}
return ans;
}
};
剑指 Offer II 019. 最多删除一个字符得到回文
线性枚举+双指针
遍历字符串,当找到对称位置的字符不同时,就分别判断删掉左边的字符和删掉右边的字符
class Solution {
bool check(string ch,int n)
{
int i=0,j=ch.size()-1;
while(i<j)
{
if(i==n) i++;
if(j==n) j--;
if(ch[i]!=ch[j]) return false;
i++,j--;
}
return true;
}
public:
bool validPalindrome(string s) {
int l=0,r=s.size()-1;
while(l<r)
{
if(s[l]!=s[r]) return check(s,l)||check(s,r);
l++,r--;
}
return true;
}
};
1332. 删除回文子序列
找规律
观察发现因为字符串中只有两种字符,所以答案其实只有三种。0:如果字符串的长度为0,则答案是0;1:如果字符串本身就是一个回文串,那么一次就可以全删掉;2:如果字符串不是回文串,那么他就一定可以分成若干个a和若干个b
class Solution {
public:
int check(string ch)
{
int l=0,r=ch.size()-1;
while(l<r)
{
if(ch[l]!=ch[r]) return 2;
l++,r--;
}
return 1;
}
int removePalindromeSub(string s) {
return !s.size()?0:check(s);
}
};