1. 程式人生 > >Hash_字串Hash_CH1402_字尾陣列

Hash_字串Hash_CH1402_字尾陣列

思路分析:

    考慮到, 為比較兩個字串按照字典序的大小關係, 可先計算出兩個字串的最長公共字首的長度, 然後在O(1)時間比較兩個字串的大小, 對於計算最長公共字首長度, 可通過字串Hash和二分或倍增在對數時間內求得, 具體請看下面AC程式碼, 第一個是基於二分, 第二個是基於倍增.

//CH1402_字尾陣列
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAX = 3e5 + 5, HEX = 1331;
unsigned long long h[MAX], p[MAX];
int SA[MAX], He[MAX], len;
char s[MAX];
//返回s[a...len - 1] < s[b...len - 1]的最長公共字首長度 
int getSameLen(int a, int b){
	int l = 0, r = min(len - 1 - a + 1, len - 1 - b + 1), mid;
	while(mid = l + r + 1 >> 1, l < r)
		if(h[a + mid] - h[a] * p[mid] == h[b + mid] - h[b] * p[mid]) l = mid;
		else r = mid - 1;
	return l; 	
}
//如果s[a...len - 1] < s[b...len - 1]返回true, 否則返回false 
bool cmp(int a, int b){
	int l = getSameLen(a, b);
	if(l == 0) return s[a] < s[b];
	if(l == len - 1 - a + 1) return true;
	if(l == len - 1 - b + 1) return false;
	return s[a + l] < s[b + l]; 
}
int main(){
	len = (scanf("%s", s), strlen(s));
	for(int i = 1; i <= len; ++i) h[i] = h[i - 1] * HEX + (s[i - 1] - 'a' + 1);
	p[0] = 1; for(int i = 1; i <= len; ++i) p[i] = p[i - 1] * HEX;
	for(int i = 1; i <= len; ++i) SA[i] = i - 1;
	sort(SA + 1, SA + len + 1, cmp);
	for(int i = 1; i <= len; ++i) cout << SA[i] << " "; cout << endl;
	//計算height
	He[1] = 0; for(int i = 2; i <= len; ++i) He[i] = getSameLen(SA[i - 1], SA[i]);
	for(int i = 1; i <= len; ++i) cout << He[i] << " "; cout << endl; 	
	return 0;
} 
//CH1402_字尾陣列
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAX = 3e5 + 5, HEX = 1331;
unsigned long long h[MAX], p[MAX];
int SA[MAX], He[MAX], len;
char s[MAX];
//返回s[a...len - 1] < s[b...len - 1]的最長公共字首長度 
int getSameLen(int a, int b){
	int begin = 0, len = 2, bound = min(::len - 1 - a + 1, ::len - 1 - b + 1), t;
	while(t = begin + len - 1, len >= 2)
		if(t <= bound && h[a + t] - h[a] * p[t] == h[b + t] - h[b] * p[t]) len <<= 1, begin = t;
		else len >>= 1;
	return begin;	
}
//如果s[a...len - 1] < s[b...len - 1]返回true, 否則返回false 
bool cmp(int a, int b){
	int l = getSameLen(a, b);
	if(l == 0) return s[a] < s[b];
	if(l == len - 1 - a + 1) return true;
	if(l == len - 1 - b + 1) return false;
	return s[a + l] < s[b + l]; 
}
int main(){
	len = (scanf("%s", s), strlen(s));
	for(int i = 1; i <= len; ++i) h[i] = h[i - 1] * HEX + (s[i - 1] - 'a' + 1);
	p[0] = 1; for(int i = 1; i <= len; ++i) p[i] = p[i - 1] * HEX;
	for(int i = 1; i <= len; ++i) SA[i] = i - 1;
	sort(SA + 1, SA + len + 1, cmp);
	for(int i = 1; i <= len; ++i) cout << SA[i] << " "; cout << endl;
	//計算height
	He[1] = 0; for(int i = 2; i <= len; ++i) He[i] = getSameLen(SA[i - 1], SA[i]);
	for(int i = 1; i <= len; ++i) cout << He[i] << " "; cout << endl; 	
	return 0;
}