feat[golang]: 添加一些go的常用工具类

This commit is contained in:
godotg
2022-09-16 13:18:59 +08:00
parent 71cd7ccdbe
commit 770c2f3380
15 changed files with 4571 additions and 0 deletions
+884
View File
@@ -13,6 +13,7 @@ package stringutil
import (
"bytes"
"fmt"
"net/url"
"regexp"
"strconv"
@@ -250,3 +251,886 @@ func UnicodeEmojiCode(s string) string {
}
return ret
}
// ----------------------------------------------------------------------------------------------------
/**
通过+号拼接字符串
*/
func AddStringWithOperator(str1, str2 string) string {
return str1 + str2
}
/**
通过strings 包的join连接字符串
*/
func AddStringWidthJoin(strArray []string) string {
return strings.Join(strArray, "")
}
/**
通过buffer 拼接字符串
*/
func AddStringWidthBuffer(strArray []string) string {
var buffer bytes.Buffer
for _, value := range strArray {
buffer.WriteString(value)
}
return buffer.String()
}
/**
反转字符串
*/
func ReversString(str string) string {
count := len(str)
bytes := make([]byte, len(str))
for i := 0; i < len(str); i++ {
bytes[i] = str[count-1-i]
}
return string(bytes)
}
/**
https://www.cnblogs.com/linghu-java/p/9037262.html 参考这边文章
查找给定字符串中的最长不重复子串
返回最长不重复子串+子串的长度
*/
func FindMaxLenNoRepeatSubStr(s string) (string, int) {
if len(s) == 1 {
return s, 1
}
head, tail := 0, 0
maxLenNoRepeatSubStr := ""
for i := 0; i < len(s)-1; i++ {
for j := i; j < len(s); j++ {
if strings.Contains(maxLenNoRepeatSubStr, s[j:j+1]) {
if head == 0 && tail == 0 {
head, tail = i, j
}
if len(s[i:j]) > len(s[head:tail]) {
head, tail = i, j
}
maxLenNoRepeatSubStr = ""
break
}
maxLenNoRepeatSubStr = s[i : j+1]
}
if maxLenNoRepeatSubStr == s[i:] && len(s[i:]) > len(s[head:tail]) {
head, tail = i, len(s)
break
}
}
return s[head:tail], tail - head
}
/**
查找给定字符串中的最长不重复子串
返回子串的长度
*/
func FindMaxLenNoRepeatSubStr2(s string) int {
length := len(s)
ans := 0
for i := 0; i < length; i++ {
for j := i + 1; j <= length; j++ {
if allUnique(s, i, j) {
if (j - i) > ans {
ans = j - i
}
}
}
}
return ans
}
func allUnique(s string, start int, end int) bool {
set := make(map[byte]int, 0)
for i := start; i < end; i++ {
if _, ok := set[s[i]]; ok {
return false
}
set[s[i]]++
}
return true
}
/**
时间滑动窗口思想
查找给定字符串中的最长不重复子串
返回子串的长度
*/
func FindMaxLenNoRepeatSubStr3(s string) int {
length := len(s)
ans := 0
m := make(map[byte]int, 0)
i, j := 0, 0
for i < length && j < length {
//如果不包含
if _, ok := m[s[j]]; !ok {
m[s[j]]++
j++
if (j - i) > ans {
ans = j - i
}
} else { //如果包含
delete(m, s[i])
i++
}
}
return ans
}
/**
从两个给定字符串中找出最长公共子串
返回最长公共子串 "gfdef", "abcdef"
*/
func FindMaxLenCommonSubStr(str1, str2 string) string {
start1 := -1
start2 := -1
longest := 0
for i := 0; i < len(str1); i++ {
for j := 0; j < len(str2); j++ {
length := 0
m := i
n := j
for m < len(str1) && n < len(str2) {
if str1[m] != str2[n] {
break
}
length++
m++
n++
}
if longest < length {
longest = length
start1 = i
start2 = j
}
}
}
if len(str1) > len(str2) {
return str1[start1 : start1+longest]
} else {
return str2[start2 : start2+longest]
}
}
// 采用动态规划求取最长公共子串
func FindMaxLenCommonSubStr2(str1, str2 string) string {
l1 := len(str1)
l2 := len(str2)
max := 0
end := 0
var twoArray [][]int
for i := 0; i < l1+1; i++ {
tmp := make([]int, l2+1)
twoArray = append(twoArray, tmp)
}
for i := 1; i <= l1; i++ {
for j := 1; j <= l2; j++ {
if str1[i-1] == str2[j-1] {
twoArray[i][j] = twoArray[i-1][j-1] + 1
if twoArray[i][j] > max {
max = twoArray[i][j]
end = j
}
} else {
twoArray[i][j] = 0
}
}
}
bytes := make([]byte, 0)
for m := end - max; m < end; m++ {
bytes = append(bytes, str2[m])
}
return string(bytes)
}
/**
求最长公共子序列
*/
func FindMaxLenCommonSubSeq(str1, str2 string) string {
l1 := len(str1)
l2 := len(str2)
bs := make([]byte, 0)
for m := 1; m <= l2; m++ {
for n := 1; n <= l1; n++ {
if str1[n-1] == str2[m-1] {
bs = append(bs, str1[n-1])
}
}
}
return Deduplicate(string(bs))
}
/**
移除字符串中的重复字符
*/
func RemoveRepeatStr(str string) string {
if len(str) == 0 {
return ""
}
bs := [256]byte{}
for _, v := range str {
bs[v] = 1
}
rs := make([]byte, 0)
for index, v := range bs {
if v == 1 {
rs = append(rs, byte(index))
}
}
return string(rs)
}
/**
去除重复的字符,返回去重后的字符
申请了新的数组用来存储,空间复杂度o(n)
*/
func Deduplicate(input string) string {
if len(input) == 0 {
return ""
}
slice := make([]rune, 0, 0)
m := make(map[rune]byte, 0)
for _, v := range input {
if _, ok := m[v]; ok {
continue
}
slice = append(slice, v)
m[v] = 0
}
return string(slice)
}
/**
去除重复的字符,返回去重后的字符
空间复杂度o(1)
*/
func Deduplicate2(input string) string {
if len(input) == 0 {
return ""
}
m := make(map[rune]byte, 0)
bs := []byte(input)
current := 0
for next, v := range input {
if _, ok := m[v]; ok {
continue
}
bs[current] = input[next]
current++
m[v] = 0
}
return string(bs[:current])
}
/**
你有一个单词列表 words 和一个模式 pattern,你想知道 words 中的哪些单词与模式匹配。
如果存在字母的排列 p ,使得将模式中的每个字母 x 替换为 p(x) 之后,我们就得到了所需的单词,那么单词与模式是匹配的。
(回想一下,字母的排列是从字母到字母的双射:每个字母映射到另一个字母,没有两个字母映射到同一个字母。)
返回 words 中与给定模式匹配的单词列表。
你可以按任何顺序返回答案。
*/
func FindAndReplacePattern(words []string, pattern string) []string {
patternWords := make([]string, 0)
for _, word := range words {
flag := true
ruleMap1 := make(map[byte]byte, len(pattern))
ruleMap2 := make(map[byte]byte, len(pattern))
for j := 0; j < len(pattern); j++ {
p := pattern[j]
w := word[j]
if _, ok := ruleMap1[p]; ok {
if ruleMap1[p] != w {
flag = false
break
}
} else if _, ok := ruleMap2[w]; ok {
flag = false
} else {
ruleMap1[p] = w
ruleMap2[w] = p
}
}
if flag {
patternWords = append(patternWords, word)
}
}
return patternWords
}
/**
判断字符串是否为空
true 为空 false 不为空
*/
func IsBlank(str string) bool {
return !(len(str) > 0)
}
/**
给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000
"abab" true "aba" false
*/
func RepeatedSubstringPattern(s string) bool {
length := len(s)
if length == 0 || length == 1 {
return false
}
n := 2
for n <= length {
mid := length / n
step := mid
index := 0
flag := true
for mid < length {
if (mid+step) > length || s[index:mid] != s[mid:mid+step] {
flag = false
break
}
index = index + step
mid = mid + step
}
if flag {
fmt.Println(step)
return true
}
n++
}
return false
}
/**
给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000
"abab" true "aba" false
*/
func RepeatedSubstringPattern2(s string) bool {
if len(s) == 0 {
return false
}
size := len(s)
ss := (s + s)[1 : size*2-1]
return strings.Contains(ss, s)
}
func GetNext(p string) []int { //ababda
next := make([]int, len(p))
next[0] = -1
k := -1
i := 0
for i < len(p)-1 {
if k == -1 || p[i] == p[k] {
k++
i++
next[i] = k
} else {
k = next[k]
}
}
fmt.Println(next)
return next
}
/**
KMP 算法,字符串模式匹配算法 主要是 GetNext
匹配 target 在 source 存在时的起始位置 (字符串搜索) "adabeabcabc", "abcabc"
*/
func StrMatch(source, target string) int {
slen := len(source)
tlen := len(target)
next := GetNext(target)
q := 0
for i := 0; i < slen; i++ {
for q > 0 && target[q] != source[i] {
q = next[q]
}
if target[q] == source[i] {
q++
}
if q == tlen {
return i - tlen + 1
}
}
return -1
}
/**
判断括号是否成对出现
输入: "()[]{}"
输出: true
输入: "(]"
输出: false
*/
func IsValid(s string) bool {
stack := make([]rune, len(s))
size := 0
for _, v := range s {
if v == '(' {
stack[size] = ')'
} else if v == '[' {
stack[size] = ']'
} else if v == '{' {
stack[size] = '}'
} else {
if size == 0 && stack[size] == 0 {
return false
}
if size-1 < 0 {
return false
}
if v != stack[size-1] {
return false
}
size--
continue
}
size++
}
if size > 0 {
return false
}
return true
}
/**
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为1000。
示例 1
输入: "babad"
输出: "bab"
注意: "aba"也是一个有效答案。
示例 2
输入: "cbbd"
输出: "bb"
*/
func LongestPalindrome(s string) string {
if len(s) == 0 || len(s) == 1 {
return s
}
head, tail := 0, len(s)-1
seq := 0
max := 1
index := 0
for head < len(s)-1 {
tail = len(s) - 1
tempHead := head
for tempHead < tail {
if s[tempHead] == s[tail] {
seq++
if tail-tempHead <= 2 {
break
}
tempHead++
tail--
continue
}
tail--
if seq > 0 {
tempHead = tempHead - seq
tail = tail + seq
seq = 0
}
}
if seq > 0 {
if (seq*2 + (tail-tempHead)/2) >= max {
max = seq*2 + (tail-tempHead)/2
index = tempHead - seq + 1
}
}
head++
seq = 0
}
return s[index : index+max]
}
/**
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
*/
func LengthOfLongestSubstring(s string) int {
next := GetNext(s)
m := make(map[byte]int, 0)
temp := 0
max := 0
for i := 0; i < len(s); i++ {
if _, ok := m[s[i]]; ok {
if max == 0 {
max = temp
}
i = next[i] - 1
m = make(map[byte]int, 0)
if temp > max {
max = temp
}
temp = 0
continue
}
m[s[i]] = 1
temp++
}
if temp > max {
max = temp
}
return max
}
/**
最长公共前缀
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 ""。
示例 1:
输入: ["flower","flow","flight"]
输出: "fl"
示例 2:
输入: ["dog","racecar","car"]
输出: ""
解释: 输入不存在公共前缀。
说明:
所有输入只包含小写字母 a-z 。
*/
func LongestCommonPrefix(strs []string) string {
if strs == nil || len(strs) == 0 {
return ""
}
bs := make([]rune, 0, 0)
strs = sort(strs)
fmt.Println(strs)
min := strs[0]
for index, v := range min {
for _, n := range strs {
if n[index] != byte(v) {
return string(bs)
}
}
bs = append(bs, v)
}
return string(bs)
}
/**
字符串按长度排序 归并
*/
func sort(strs []string) []string {
if len(strs) == 1 {
return strs
}
mid := len(strs) / 2
left := sort(strs[:mid])
right := sort(strs[mid:])
return merger(left, right)
}
func merger(left []string, right []string) []string {
s := make([]string, 0, 0)
l, r := 0, 0
for l < len(left) && r < len(right) {
if len(left[l]) < len(right[r]) {
s = append(s, left[l])
l++
} else if len(left[l]) > len(right[r]) {
s = append(s, right[r])
r++
} else {
s = append(s, left[l])
s = append(s, right[r])
l++
r++
}
}
for l < len(left) {
s = append(s, left[l])
l++
}
for r < len(right) {
s = append(s, right[r])
r++
}
return s
}
/**
字符串全排列
题目:终端随机输入一串字符串,输出该字符串的所有排列。
  例如,输入:“abc”,输出:abc、acb、bac、bca、cab、cba
*/
func RecursionPermutation(str string) []string {
arrays := make([]string, 0, 0)
arrays = permutation([]byte(str), 0, arrays)
return arrays
}
func permutation(s []byte, i int, arrays []string) []string {
if i == len(s)-1 {
arrays = append(arrays, string(s))
return arrays
}
for temp := i; temp < len(s); temp++ {
s[i], s[temp] = s[temp], s[i]
arrays = permutation(s, i+1, arrays)
s[i], s[temp] = s[temp], s[i]
}
return arrays
}
/**
给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列。
换句话说,第一个字符串的排列之一是第二个字符串的子串。
示例1:
输入: s1 = "ab" s2 = "eidbaooo"
输出: True
解释: s2 包含 s1 的排列之一 ("ba").
示例2:
输入: s1= "ab" s2 = "eidboaoo"
输出: FalseRecursionPermutation
*/
//我们不用真的去算出s1的全排列,只要统计字符出现的次数即可。可以使用一个哈希表配上双指针来做
func CheckInclusion(s1 string, s2 string) bool {
if len(s1) > len(s2) {
return false
}
m := make(map[rune]byte, 0)
for index, v := range s1 {
m[v]++
m[rune(s2[index])]--
}
if allZero(m) {
return true
}
for temp := len(s1); temp < len(s2); temp++ {
m[rune(s2[temp])]--
m[rune(s2[temp-len(s1)])]++
if allZero(m) {
return true
}
}
return false
}
func allZero(m map[rune]byte) bool {
for _, v := range m {
if v != 0 {
return false
}
}
return true
}
/**
给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。
示例 1:
输入: num1 = "2", num2 = "3"
输出: "6"
示例 2:
输入: num1 = "123", num2 = "456"
输出: "56088"
说明:
num1 和 num2 的长度小于110。
num1 和 num2 只包含数字 0-9。
num1 和 num2 均不以零开头,除非是数字 0 本身。
不能使用任何标准库的大数类型(比如 BigInteger)或直接将输入转换为整数来处理。
*/
func Multiply(num1 string, num2 string) string {
m := make(map[int]int, 0)
value := 0
// 映射0 到9 的ASCII码
for i := 48; i < 58; i++ {
m[i] = value
value++
}
n1 := len(num1)
n2 := len(num2)
result := make([]int, n1+n2)
rss := make([][]int, 0, 0)
index := n1 + n2 - 1
for t := len(num1) - 1; t >= 0; t-- {
var j, y int = 0, 0
for temp := len(num2) - 1; temp >= 0; temp-- {
k := m[int(num1[t])] * m[int(num2[temp])]
y = (k + j) % 10
j = (k + j) / 10
result[index] = y
index--
if temp == 0 { //如果到最高位了,就把商赋值
result[index] = j
}
}
index = index + len(num2) - 1
rss = append(rss, result)
result = make([]int, n1+n2)
}
fmt.Println(rss)
index = n1 + n2 - 1
var sum int = 0
var j, y int = 0, 0
for m := index; m >= 0; m-- {
for i := 0; i < len(rss); i++ {
sum = sum + rss[i][m]
}
y = sum % 10
if y+j < 10 {
result[m] = y + j
j = sum / 10
} else {
result[m] = (y + j) % 10
j = sum/10 + (y+j)/10
}
sum = 0
}
for index, v := range result {
if index == len(result)-1 && v == 0 {
return "0"
}
if v == 0 {
continue
}
result = result[index:]
break
}
s := make([]string, len(result), len(result))
for index, v := range result {
fmt.Println(v)
s[index] = string(strconv.Itoa(int(v)))
}
fmt.Println(result)
fmt.Println(s)
return strings.Join(s, "")
}
func LetterCasePermutation(S string) []string {
if len(S) == 0 {
return nil
}
temps := ""
position := 0
sArray := make([]string, 0, 0)
sArray = dfs(temps, S, sArray, position)
return sArray
}
// 65-90 大写
// 97-122 小写
func dfs(temps string, s string, sArray []string, position int) []string {
if position == len(s) {
sArray = append(sArray, temps)
return sArray
}
//不是字母
if s[position] < 65 || s[position] > 122 || (s[position] > 90 && s[position] < 97) {
sArray = dfs(temps+string(rune(s[position])), s, sArray, position+1)
} else {
sArray = dfs(temps+strings.ToLower(string(rune(s[position]))), s, sArray, position+1)
sArray = dfs(temps+strings.ToUpper(string(rune(s[position]))), s, sArray, position+1)
}
return sArray
}
// Split replaces strings.Split.
// strings.Split has a giant pit because strings.Split ("", ",") will return a slice with an empty string.
func Split(s, sep string) []string {
if s == "" {
return []string{}
}
return strings.Split(s, sep)
}
// JoinStrSkipEmpty concatenates multiple strings to a single string with the specified separator and skips the empty
// string.
func JoinStrSkipEmpty(sep string, s ...string) string {
var buf bytes.Buffer
for _, v := range s {
if v == "" {
continue
}
if buf.Len() > 0 {
buf.WriteString(sep)
}
buf.WriteString(v)
}
return buf.String()
}
// JoinStr concatenates multiple strings to a single string with the specified separator.
// Note that JoinStr doesn't skip the empty string.
func JoinStr(sep string, s ...string) string {
var buf bytes.Buffer
for i, v := range s {
if i != 0 {
buf.WriteString(sep)
}
buf.WriteString(v)
}
return buf.String()
}
// ReverseStr reverses the specified string without modifying the original string.
func ReverseStr(s string) string {
rs := []rune(s)
var r []rune
for i := len(rs) - 1; i >= 0; i-- {
r = append(r, rs[i])
}
return string(r)
}
// GetAlphanumericNumByASCII gets the alphanumeric number based on the ASCII code value.
// Note that this function has a better performance than GetAlphanumericNumByRegExp, so this function is recommended.
func GetAlphanumericNumByASCII(s string) int {
num := int(0)
for i := 0; i < len(s); i++ {
switch {
case 48 <= s[i] && s[i] <= 57: // digits
fallthrough
case 65 <= s[i] && s[i] <= 90: // uppercase letters
fallthrough
case 97 <= s[i] && s[i] <= 122: // lowercase letters
num++
default:
}
}
return num
}
// GetAlphanumericNumByASCIIV2 gets the alphanumeric number based on the ASCII code value.
// Because range by rune so the performance is worse than GetAlphanumericNumByASCII.
func GetAlphanumericNumByASCIIV2(s string) int {
num := int(0)
for _, c := range s {
switch {
case '0' <= c && c <= '9':
fallthrough
case 'a' <= c && c <= 'z':
fallthrough
case 'A' <= c && c <= 'Z':
num++
default:
}
}
return num
}
// GetAlphanumericNumByRegExp gets the alphanumeric number based on regular expression.
// Note that this function has a poor performance when compared to GetAlphanumericNumByASCII,
// so the GetAlphanumericNumByASCII is recommended.
func GetAlphanumericNumByRegExp(s string) int {
rNum := regexp.MustCompile(`\d`)
rLetter := regexp.MustCompile("[a-zA-Z]")
return len(rNum.FindAllString(s, -1)) + len(rLetter.FindAllString(s, -1))
}