题目概述

链接:点我做题
一、哈希表
我们观察到所有能组成回文序列的字符串,如果字符串长度是偶数,那么它每个字符的数量一定是偶数;如果字符串长度是奇数,那么它一定只有一个字符数量是奇数,其余字符数量是偶数。综上所述,不管字符长度是奇数还是偶数,它最多只有一个字符的数量是奇数,其余字符数量一定是偶数,不满足条件的就返回
f
a
l
s
e
false
false.
代码:
class Solution {
public:
bool canPermutePalindrome(string s)
{
unordered_map<char, int> hash;
int expectnum = 0;
for (auto e : s)
{
hash[e]++;
}
for (auto e : hash)
{
if ((e.second) % 2 != 0)
{
if (expectnum == 0)
{
expectnum++;
}
else
{
return false;
}
}
}
return true;
}
};
时间复杂度:
O
(
n
)
O(n)
O(n)
空间复杂度:
O
(
n
)
O(n)
O(n)
二、位运算
我们知道,拓展后的ASCII码表有256位,如果每一位用一个
b
i
t
bit
bit来表示它的状态,如0x 00 00 00 01表示ASCII码表的1,0x 00 00 00 02表示ASCII码表的2,0x 00 00 00 04表示ASCII码表的3…那么用一个含8个int的数组都能装得下一个由对应位为1其他位为0表示的ASCII码。
我们知道 a^a = 0,回文子串一定只有一个字符的数量是奇数个,其余字符的数量是偶数个,那么把这个字符串的每一位都转化为这样表示的ASCII码,它们异或起来的结果一定是最多只含一个
b
i
t
bit
bit位是1的字符,而我们知道对于一个二进制位表示的x,
x
&
(
x
−
1
)
x\&(x-1)
x&(x−1)的值是去掉x从左往右数第一个1后二进制位表示的值,具体详细证明可以参考这篇我的博客Brian Kernighan算法,因此我们可以利用
x
&
=
x
−
1
x\&=x-1
x&=x−1让x到0进行操作的次数是否为1来判断x是否最多只有一个1bit。
困难点还在于如何让一个8个int的数组去正确的表示这种ASCII码,我们可以利用整除\和取余%来获得这种ASCII码,具体来说,一个int32位,所以整除32得到对应数组位置,再右移取余32的值就可以到达对应位置。
代码:
class Solution {
public:
bool canPermutePalindrome(string s)
{
//位运算 用一个8个int的数组
//每一字符 生成一个右移到它ascii码位置的int
//然后让这个数组对应的位置去异或上这个int
//回文序列保证最后整个数组里头最多有一个1
int arr[8] = {0};
for (auto e : s)
{
//一个int32位 先整除32到达它在哪个数组里
//然后右移取余32位就是对应为位置
arr[e / 32] ^= (1 << (e % 32));
}
int cnt = 0;
for (auto e : arr)
{
while (e != 0)
{
e &= (e - 1);
cnt++;
}
}
return cnt < 2;
}
};
时间复杂度:
O
(
n
)
O(n)
O(n)
空间复杂度:
O
(
1
)
O(1)
O(1),8个int数组属于是常数级大小而不是变量级。
本文介绍了一种通过哈希表和位运算判断字符串是否可以通过重新排列形成回文的方法。使用哈希表时,只需遍历一次字符串即可完成判断,时间复杂度为O(n),空间复杂度也为O(n)。采用位运算时,通过对ASCII码进行特殊处理,不仅保持了O(n)的时间复杂度,还将空间复杂度降低至O(1)。
1005

被折叠的 条评论
为什么被折叠?



