【代码随想录——字符串】

1. KMP算法

最长相等前后缀

1.1 如何计算前缀表

  • 前缀:是包含首字母,不包含尾字母的所有子串
  • 后缀:是包含尾字母,不包含首字母的所有子串
    求最长相等前后缀的长度

假设我们有一个模式串:aabaaf

模式最长相等前后缀最长相等前后缀的长度
a0
aaa1
aab0
aabaa1
aabaaaa2
aabaaf0

对于aabaaf我们得到了一个前缀表010120

1.2 如何使用前缀表

假设我们有一个字符串aabaabaaf,
对应的模式串和前缀表如下

序号012345
模式串aabaaf
前缀表010120
  1. 当我们匹配模式串到f的时候发现匹配不下去了
  2. 那我们查看f前一位所对应的前缀表所对应的值,如果不为0,则继续3。否则结束,字符串的匹配起点向后移动
  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
}
  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值