1. KMP算法
最长相等前后缀
1.1 如何计算前缀表
- 前缀:是包含首字母,不包含尾字母的所有子串
- 后缀:是包含尾字母,不包含首字母的所有子串
求最长相等前后缀的长度
假设我们有一个模式串:aabaaf
模式 | 最长相等前后缀 | 最长相等前后缀的长度 |
---|---|---|
a | 无 | 0 |
aa | a | 1 |
aab | 无 | 0 |
aaba | a | 1 |
aabaa | aa | 2 |
aabaaf | 无 | 0 |
对于aabaaf我们得到了一个前缀表010120
1.2 如何使用前缀表
假设我们有一个字符串aabaabaaf,
对应的模式串和前缀表如下
序号 | 0 | 1 | 2 | 3 | 4 | 5 |
模式串 | a | a | b | a | a | f |
前缀表 | 0 | 1 | 0 | 1 | 2 | 0 |
- 当我们匹配模式串到f的时候发现匹配不下去了
- 那我们查看f前一位所对应的前缀表所对应的值,如果不为0,则继续3。否则结束,字符串的匹配起点向后移动
- 之后从模式串的这一位继续匹配,如果再不匹配,则继续刚才的过程
1.3 next数组/prefix数组(其实就是前缀表)
next数组会告诉我们要回退到哪里。
- 前缀表无减一:查看不匹配字符前一位所对应的前缀表所对应的值
- 前缀表右移一位:最前面用-1补全,查看不匹配字符所对应的前缀表所对应的值
- 前缀表减一:查看不匹配字符前一位所对应的前缀表所对应的值,并+1
1.4 代码实现
func strStr(haystack string, needle string) int {n := len(needle)if n ==0 {return 0}j := 0next := 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){// 寻找[0:i]中最长相等前后缀的长度// i指向后缀末尾位置 ;j表示前缀需要和后缀匹配的位置indexj := 0next[0] = jfor 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}
}
2. 反转字符串
func reverseString(s []byte) {n := len(s)for i:=0;i<n/2;i++{s[i],s[n-1-i] = s[n-1-i],s[i]}
}
3. 反转字符串②
func reverseStr(s string, k int) string {chars := []byte(s)n := len(s)i := 2 * kfor ; i < n; i += 2 * k {//每有2k个翻转前部分reverse(chars, i-2*k, i-k-1)}// 检查最后剩下的一部分if n-(i-2*k) < k {reverse(chars, i-2*k, n-1)} else {reverse(chars, i-2*k, i-k-1)}return string(chars)
}func reverse(s []byte, begin, end int) {for begin < end {s[begin], s[end] = s[end], s[begin]begin++end--}
}
4. 替换数字
https://kamacoder.com/problempage.php?pid=1064
package mainimport ("fmt"
)func main() {var s stringfmt.Scan(&s) // 等待用户输入文本并按下回车fmt.Println(solution(s))
}func solution(s string) string {number := []byte("number")chars := []byte(s)res := make([]byte, 0)for i := 0; i < len(chars); i++ {if chars[i] >= '0' && chars[i] <= '9' {res = append(res, number...)} else {res = append(res, chars[i])}}return string(res)
}
5. 翻转字符串里的单词
func reverseWords(s string) string {chars := []byte(s)// 第一步,先清除一下左右两端多余的空格firstMeetCharIndex := -1lastMeetCharIndex := -1for i := 0; i < len(chars); i++ {if chars[i] != ' ' {lastMeetCharIndex = iif firstMeetCharIndex == -1 {firstMeetCharIndex = i}}}newChars := chars[firstMeetCharIndex : lastMeetCharIndex+1]//清除一下字符串中的多余的空格count := 0isSpace := falsefor i := 0; i < len(newChars); i++ {if newChars[i] == ' ' {if isSpace {continue}isSpace = true} else {isSpace = false}chars[count] = newChars[i]count++}// 反转整个数组reverse(chars, 0, count-1)// 反转单词p1, p2 := -1, -1for i := 0; i < count; i++ {if chars[i] == ' ' {p1 = p2p2 = ireverse(chars, p1+1, p2-1)}}reverse(chars, p2+1, count-1)return string(chars[:count])
}func reverse(s []byte, begin, end int) {for begin < end {s[begin], s[end] = s[end], s[begin]begin++end--}
}
6. 右旋转字符串
package mainimport ("fmt"
)func main() {var n intvar s stringfmt.Scanln(&n)fmt.Scanln(&s) // 等待用户输入文本并按下回车fmt.Println(solution(s, n))
}func solution(s string, n int) string {return s[len(s)-n:] + s[0:len(s)-n]
}
7. 实现strStr()
func strStr(haystack string, needle string) int {for i:=0;i<=len(haystack)-len(needle);i++{if isFit(haystack,needle,i){return i}}return -1
}func isFit(haystack,needle string,index int)bool{for i:=0;i<len(needle);i++{if haystack[index+i]!=needle[i]{return false}}return true
}
8. 重复的子字符串
func repeatedSubstringPattern(s string) bool {n := len(s)next := prefixTable(s)if next[n-1] != 0 && n%(n-next[n-1]) == 0 {return true}return false
}func prefixTable(s string) []int {j := 0 //前缀匹配到的位置res := make([]int, len(s))res[0] = 0for i := 1; i < len(s); i++ {for j > 0 && s[i] != s[j] {j = res[j-1]}if s[i] == s[j] {j++}res[i] = j}return res
}