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 := 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){
// 寻找[0:i]中最长相等前后缀的长度
// i指向后缀末尾位置 ;j表示前缀需要和后缀匹配的位置index
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
}
}
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 * k
for ; 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 main
import (
"fmt"
)
func main() {
var s string
fmt.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 := -1
lastMeetCharIndex := -1
for i := 0; i < len(chars); i++ {
if chars[i] != ' ' {
lastMeetCharIndex = i
if firstMeetCharIndex == -1 {
firstMeetCharIndex = i
}
}
}
newChars := chars[firstMeetCharIndex : lastMeetCharIndex+1]
//清除一下字符串中的多余的空格
count := 0
isSpace := false
for 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, -1
for i := 0; i < count; i++ {
if chars[i] == ' ' {
p1 = p2
p2 = i
reverse(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 main
import (
"fmt"
)
func main() {
var n int
var s string
fmt.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] = 0
for 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
}