全排列哈希
我们熟知的数一般都是常进制数,所谓常进制数就是该数的每一位都是常数进制:
- k进制数上的每一位都逢k进一, 第i位的位权是
k
i
k^i
ki
这里要介绍一种变进制数,用来表示字符串的排列状态 - 这种数的第i位逢i进一,第i位的位权是 i ! i! i!
- 用d[i]来表示一个变进制数第i位上的数字
- 一个n位变进制数的值就为
∑
i
=
0
n
−
1
d
[
i
]
×
i
!
\sum\limits^{n - 1}_{i=0}d[i]×i!
i=0∑n−1d[i]×i!
这是一个最大的9位变进制数
876543210
它对应的十进制数为
8 × 8! + 7 × 7! + 6 × 6! + …… + 1 × 1! + 0 × 0! = 9! - 1 = 362879
我们可以找到一个9位变进制数,与一个9位无重复串的某种排列一一对应
用d[i]表示字符串中的第i位与其前面的字符组成的逆序对个数
字符串的一种排列对应的变进制数的值为
∑
i
=
0
n
−
1
d
[
i
]
×
i
!
\sum\limits^{n−1}_{i=0}d[i]×i!
i=0∑n−1d[i]×i!
这是字符串123x46758的与d[i]d[i]的对应关系
i 0 1 2 3 4 5 6 7 8
s[i] 1 2 3 x 4 6 7 5 8
d[i] 0 0 0 0 1 1 1 3 1
它对应的变进制数的值为
1 × 4! + 1 × 5! + 1 × 6! + 3 × 7! + 1 × 8! = 56304
因此可以用以下函数求字符串的一种排列对应的哈希值
int permutation_hash(char s[], int n) //求长度为n的字符串某种排列的哈希值
{
int ans = 0;
for(int i = 0; i < n; i ++)
{
int d = 0;
for(int j = 0; j < i; j ++)
if(s[j] > s[i]) d ++; //求s[i]与其前面的字符组成的逆序对个数
ans += d * fact[i];
}
return ans;
}
n不能太大,通常不超过12,否则会溢出
时间复杂度为O(n²)