前言
算法真是博大精深,真是人想出来的吗。。。
内容
一、动态口令
某公司门禁密码使用动态口令技术。初始密码为字符串 password
,密码更新均遵循以下步骤:
- 设定一个正整数目标值
target
- 将
password
前target
个字符按原顺序移动至字符串末尾
请返回更新后的密码字符串。
切片
func dynamicPassword(password string, target int) string {
return password[target:]+password[0:target]
}
思路二
1. 反转前n个字符
2. 反转第n到end字符
3. 反转整个字符
func dynamicPassword(password string,target int)string{
ss:=[]byte(password)
n:=len(ss)
// 1. 反转前n个字符
// 2. 反转第n到end字符
// 3. 反转整个字符
reverse(ss,0,target-1)
reverse(ss,target,n-1)
reverse(ss,0,n-1)
return string(ss)
}
// 切片是引用传递
func reverse(s []byte,left,right int){
//n:=len(s)
// left,right:=0,n-1
for left<right{
s[left],s[right]=s[right],s[left]
left++
right--
}
}
二、找出字符串中第一个匹配项的下标
给你两个字符串 haystack
和 needle
,请你在 haystack
字符串中找出 needle
字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle
不是 haystack
的一部分,则返回 -1
。
暴力匹配
func strStr(haystack string, needle string) int {
n,m:=len(haystack),len(needle)
outer:
for i:=0;i+m<=n;i++{
for j:=range needle{
if haystack[i+j]!=needle[j]{
continue outer
}
}
return i
}
return -1
}
func strStr(haystack string,needle string) int{
if needle==""{
return 0
}
for i:=0;i<=len(haystack)-len(needle);i++{
if haystack[i:i+len(needle)]==needle{
return i
}
}
return -1
}
kmp算法
还不太懂
func strStr(haystack string,needle string) int{
n:=len(needle)
if n==0{
return 0
}
j:=0
next:=make([]int,n)
getNext(next,needle)
for i:=0;i<len(haystack);i++{
for j>0&&haystack[i]!=needle[j]{
j=next[j-1]
}
if haystack[i]==needle[j]{
j++
}
if j==n{
return i-n+1
}
}
return -1
}
func getNext(next []int,s string){
//j指向前缀末尾位置,i指向后缀末尾位置
j:=0
next[0]=j
for i:=1;i<len(s);i++{
for j>0&&s[i]!=s[j]{
j=next[j-1]// 向前回退
}
if s[i]==s[j]{// 找到相同的前后缀
j++
}
next[i]=j// 将j(前缀的长度)赋给next[i]
}
}
//此时如果输入的模式串为aabaaf,对应的next为 0 1 0 1 2 0,(其实这就是前缀表的数值了)
KMP算法时间复杂度是O(n+m)
暴力解法是O(n × m)
KMP的主要思想是当出现字符串不匹配时,可以知道一部分之前已经匹配的文本内容,可以利用这些信息避免从头再去做匹配了
前缀表是用来回退的,它记录了模式串与主串(文本串)不匹配的时候,模式串应该从哪里开始重新匹配
什么是前缀表:记录下标i之前(包括i)的字符串中,有多大长度的相同前缀后缀。
前缀是指不包含最后一个字符的所有以第一个字符开头的连续子串。
后缀是指不包含第一个字符的所有以最后一个字符结尾的连续子串
构造next数组其实就是计算模式串s,前缀表的过程。 主要有如下三步:
初始化
处理前后缀不相同的情况
处理前后缀相同的情况
最后
早日弄懂kmp。