LeetCode438
滑动窗口,相比应该不用多说了,就是一个抽象的窗口,每次验证窗口内的值。
但是本题其实也可以不算滑动窗口,因为这个窗口是定长的,相当于每次的移动方式是已知的。
就变成了一个定长滑动字符串匹配问题。
每次对窗口内的字符串排序,然后比较:
var q []byte
func findAnagrams(s string, p string) []int {
ans:=make([]int,0)
if len(s)<len(p){
return ans
}
l,r:=0,len(p)-1
tmp:=[]byte(s[:len(p)])
ss:=strings.Split(p,"")
sort.Strings(ss)
p=strings.Join(ss,"")
for r<len(s){
if check(tmp,p){
ans=append(ans,l)
}
r++
l++
if r<len(s){
tmp=append(tmp,s[r])
}
tmp=tmp[1:]
}
return ans
}
func check(a []byte,o string)bool{
//fmt.Println(string(a),o)
q=make([]byte,len(a))
copy(q,a)
sort.Sort(sortRunes(q))
return string(q)==o
}
type sortRunes []byte
func (s sortRunes) Less(i, j int) bool {
return s[i] < s[j]
}
func (s sortRunes) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func (s sortRunes) Len() int {
return len(s)
}
没啥悬念,超时了。怎么优化呢
其实按照以往思路,也可以写个统计数组,来记录每个字符出现的次数。
官姐有写,算是比较常规的方法,不展开了。
哈希这个东西,就很神奇,可以把一个字符串映射成一个数,这样子滑动窗口验证
的时候,就只需要比较两次。
但是普通哈希,不同顺序的值是不一样的呀,比如,"abc"
的哈希值一定要和"cba"
不一样,这样有和题目要求冲突了,怎么办呢?
我们可以自定义哈希函数,这里笔者用了双哈希,其实单哈希也可以,主要是自定义哈希函数比较重要。
我定义:
hash
函数 f 1 ( s ) = ( ∑ i 0 → l e n ( n o w S t r ) − 1 i n t 64 ( n o w S t r [ i ] ) 2 ) m o d M o d 1 f1(s)=(\displaystyle \sum^{}_{i 0\to len(nowStr)-1}{int64(nowStr[i])^2})mod\:Mod1 f1(s)=(i0→len(nowStr)−1∑int64(nowStr[i])2)modMod1
hash
函数 f 2 ( s ) = ( ∑ i 0 → l e n ( n o w S t r ) − 1 i n t 64 ( n o w S t r [ i ] ) 3 ) m o d M o d 2 f2(s)=(\displaystyle \sum^{}_{i 0\to len(nowStr)-1}{int64(nowStr[i])^3})mod\:Mod2 f2(s)=(i0→len(nowStr)−1∑int64(nowStr[i])3)modMod2
其实就是各位数的平方和
与各位数的立方和
,Mod1
与Mod2
是两个大整数,用来减少哈希冲突的。
var q []byte
var mod1,mod2 int64
func findAnagrams(s string, p string) []int {
mod1=1e15+7
mod2=1e15+9
ans:=make([]int,0)
if len(s)<len(p){
return ans
}
l,r:=0,len(p)-1
now:=cal(s[:len(p)])
pp:=cal(p)
for r<len(s){
if check(now,pp){
ans=append(ans,l)
}
r++
if r<len(s){
now[0]+=int64(s[r])*int64(s[r])
now[1]+=int64(s[r])*int64(s[r])*int64(s[r])
now[0]%=mod1
now[1]%=mod2
}
now[0]-=int64(s[l])*int64(s[l])
now[1]-=int64(s[l])*int64(s[l])*int64(s[l])
now[0]=(now[0]+mod1)%mod1
now[1]=(now[1]+mod2)%mod2
l++
}
return ans
}
func cal(s string)(ans []int64){
a,b:=int64(0),int64(0)
for i:=range s{
a+=int64(s[i])*int64(s[i])
b+=int64(s[i])*int64(s[i])*int64(s[i])
a%=mod1
b%=mod2
}
ans=append(ans,a,b)
return
}
func check(a,b []int64)bool{
return a[0]==b[0] && a[1]==b[1]
}
题目描述当中,没有规定len(s)≥len(p)
,所以需要进行特判。