# 字符串
Go 标准库源码解析 - 文本操作:https://blog.twelveeee.top/2023/Go/Lib/strings/
# 算法题
# 1. 转换成小写字母
https://leetcode.cn/problems/to-lower-case/description/
https://github.com/Twelveeee/AlgorithmCamp2023/blob/main/12_String/level_1/topic_1.go
给你一个字符串
s
,将该字符串中的大写字母转换成相同的小写字母,返回新的字符串。
func toLowerCase(s string) string { | |
return strings.ToLower(s) | |
} | |
func toLowerCaseV2(s string) string { | |
ans := strings.Builder{} | |
ans.Grow(len(s)) | |
for _, ch := range s { | |
if ch >= 'A' && ch <= 'Z' { | |
ch += 32 | |
} | |
ans.WriteRune(ch) | |
} | |
return ans.String() | |
} |
# 2. 字符串转换整数
https://leetcode.cn/problems/string-to-integer-atoi/description/
https://github.com/Twelveeee/AlgorithmCamp2023/blob/main/12_String/level_1/topic_2.go
请你来实现一个
myAtoi(string s)
函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的atoi
函数)。函数
myAtoi(string s)
的算法如下:
- 读入字符串并丢弃无用的前导空格
- 检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结果是负数还是正数。 如果两者都不存在,则假定结果为正。
- 读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。
- 将前面步骤读入的这些数字转换为整数(即,"123" -> 123, "0032" -> 32)。如果没有读入数字,则整数为
0
。必要时更改符号(从步骤 2 开始)。- 如果整数数超过 32 位有符号整数范围
[−231, 231 − 1]
,需要截断这个整数,使其保持在这个范围内。具体来说,小于−231
的整数应该被固定为−231
,大于231 − 1
的整数应该被固定为231 − 1
。- 返回整数作为最终结果。
注意:
- 本题中的空白字符只包括空格字符
' '
。- 除前导空格或数字后的其余字符串外,请勿忽略 任何其他字符。
func myAtoi(s string) int { | |
i, ans, n := 0, 0, len(s) | |
flag := 1 | |
for i < n && s[i] == ' ' { | |
i++ | |
} | |
if i < n && s[i] == '-' { | |
flag = -1 | |
i++ | |
} else if i < n && s[i] == '+' { | |
i++ | |
} | |
for i < n { | |
if s[i] < '0' || s[i] > '9' { | |
return ans * flag | |
} | |
ans *= 10 | |
ans += int(s[i] - '0') | |
if ans*flag < math.MinInt32 { | |
return math.MinInt32 | |
} else if ans*flag > math.MaxInt32 { | |
return math.MaxInt32 | |
} | |
i++ | |
} | |
return ans * flag | |
} |
# 3. 反转字符串
https://leetcode.cn/problems/reverse-string/description/
https://github.com/Twelveeee/AlgorithmCamp2023/blob/main/12_String/level_2/topic_1.go
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组
s
的形式给出。不要给另外的数组分配额外的空间,你必须原地改输入数组、使用 O (1) 的额外空间解决这一问题。
func reverseString(s []byte) { | |
for i := 0; i < len(s)/2; i++ { | |
s[i], s[len(s)-1-i] = s[len(s)-1-i], s[i] | |
} | |
} |
# 4. 反转字符串 II
https://leetcode.cn/problems/reverse-string-ii/
https://github.com/Twelveeee/AlgorithmCamp2023/blob/main/12_String/level_2/topic_2.go
给定一个字符串
s
和一个整数k
,从字符串开头算起,每计数至2k
个字符,就反转这2k
字符中的前k
个字符。
- 如果剩余字符少于
k
个,则将剩余字符全部反转。- 如果剩余字符小于
2k
但大于或等于k
个,则反转前k
个字符,其余字符保持原样。
func reverseStr(s string, k int) string { | |
ans := []byte(s) | |
times := len(s) / (2 * k) | |
if len(s)%(2*k) != 0 { | |
times++ | |
} | |
for i := 0; i <= times; i++ { | |
left, rihgt := i*2*k, (i*2*k)+k | |
if rihgt > len(s) { | |
rihgt = len(s) | |
} | |
for j := 0; j < (rihgt-left)/2; j++ { | |
ans[left+j], ans[rihgt-j-1] = ans[rihgt-j-1], ans[left+j] | |
} | |
} | |
return string(ans) | |
} |
# 5. 仅仅反转字母
https://leetcode.cn/problems/reverse-only-letters/description/
https://github.com/Twelveeee/AlgorithmCamp2023/blob/main/12_String/level_2/topic_3.go
给你一个字符串
s
,根据下述规则反转字符串:
- 所有非英文字母保留在原有位置。
- 所有英文字母(小写或大写)位置反转。
返回反转后的
s
。
func reverseOnlyLetters(s string) string { | |
ans := []byte(s) | |
w := 0 | |
for i := len(s) - 1; i >= 0; i-- { | |
if s[i] > 'z' || s[i] < 'A' || (s[i] > 'Z' && s[i] < 'a') { | |
continue | |
} | |
for w < len(ans) && (ans[w] > 'z' || ans[w] < 'A' || (ans[w] > 'Z' && ans[w] < 'a')) { | |
w++ | |
} | |
ans[w] = s[i] | |
w++ | |
} | |
return string(ans) | |
} |
# 5. 仅仅反转字母
https://leetcode.cn/problems/reverse-only-letters/description/
https://github.com/Twelveeee/AlgorithmCamp2023/blob/main/12_String/level_2/topic_3.go
给你一个字符串
s
,根据下述规则反转字符串:
- 所有非英文字母保留在原有位置。
- 所有英文字母(小写或大写)位置反转。
返回反转后的
s
。
func reverseOnlyLetters(s string) string { | |
ans := []byte(s) | |
w := 0 | |
for i := len(s) - 1; i >= 0; i-- { | |
if s[i] > 'z' || s[i] < 'A' || (s[i] > 'Z' && s[i] < 'a') { | |
continue | |
} | |
for w < len(ans) && (ans[w] > 'z' || ans[w] < 'A' || (ans[w] > 'Z' && ans[w] < 'a')) { | |
w++ | |
} | |
ans[w] = s[i] | |
w++ | |
} | |
return string(ans) | |
} |
# 6. 验证回文串
https://leetcode.cn/problems/valid-palindrome/description/
https://github.com/Twelveeee/AlgorithmCamp2023/blob/main/12_String/level_2/topic_4.go
如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。
字母和数字都属于字母数字字符。
给你一个字符串
s
,如果它是 回文串 ,返回true
;否则,返回false
。
func isPalindrome(s string) bool { | |
left, right := 0, len(s)-1 | |
for left < right { | |
for left < right && !isLetter(s[left]) { | |
left++ | |
} | |
for left < right && !isLetter(s[right]) { | |
right-- | |
} | |
if !sameByte(s[left], s[right]) { | |
return false | |
} | |
right-- | |
left++ | |
} | |
return true | |
} | |
func isLetter(a byte) bool { | |
// 48 57 65 90 97 122 | |
// '0', '9', 'A', 'Z', 'a', 'z' | |
if a >= 'a' && a <= 'z' { | |
return true | |
} | |
if a >= 'A' && a <= 'Z' { | |
return true | |
} | |
if a >= '0' && a <= '9' { | |
return true | |
} | |
return false | |
} | |
func sameByte(a, b byte) bool { | |
if a == b { | |
return true | |
} | |
if '0' >= a && a <= '9' { | |
return false | |
} | |
if diff := int(a) - int(b); diff == -32 || diff == 32 { | |
return true | |
} | |
return false | |
} |
# 7. 字符串中的第一个唯一字符
https://leetcode.cn/problems/valid-palindrome/description/
https://github.com/Twelveeee/AlgorithmCamp2023/blob/main/12_String/level_2/topic_5.go
如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。
字母和数字都属于字母数字字符。
给你一个字符串
s
,如果它是 回文串 ,返回true
;否则,返回false
。
func firstUniqChar(s string) int { | |
list := make([]int, 26) | |
for _, v := range s { | |
list[v-'a']++ | |
} | |
for i, v := range s { | |
if list[v-'a'] == 1 { | |
return i | |
} | |
} | |
return -1 | |
} |
# 8. 最长公共前缀
https://leetcode.cn/problems/longest-common-prefix/description/
https://github.com/Twelveeee/AlgorithmCamp2023/blob/main/12_String/level_3/topic_1.go
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串
""
。
func longestCommonPrefix(strs []string) string { | |
if len(strs) == 1 { | |
return strs[0] | |
} | |
minLen := math.MaxInt32 | |
var ans []byte | |
for _, str := range strs { | |
if minLen > len(str) { | |
minLen = len(str) | |
} | |
} | |
for i := 0; i < minLen; i++ { | |
firstChar := strs[0][i] | |
for _, str := range strs { | |
if firstChar != str[i] { | |
return string(ans) | |
} | |
} | |
ans = append(ans, firstChar) | |
} | |
return string(ans) | |
} |
# 9. 压缩字符串
https://leetcode.cn/problems/string-compression/
https://github.com/Twelveeee/AlgorithmCamp2023/blob/main/12_String/level_3/topic_2.go
给你一个字符数组
chars
,请使用下述算法压缩:从一个空字符串
s
开始。对于chars
中的每组 连续重复字符 :
- 如果这一组长度为
1
,则将字符追加到s
中。- 否则,需要向
s
追加字符,后跟这一组的长度。压缩后得到的字符串
s
不应该直接返回 ,需要转储到字符数组chars
中。需要注意的是,如果组长度为10
或10
以上,则在chars
数组中会被拆分为多个字符。请在 修改完输入数组后 ,返回该数组的新长度。
你必须设计并实现一个只使用常量额外空间的算法来解决此问题。
func compress(chars []byte) int { | |
if len(chars) <= 1 { | |
return 1 | |
} | |
pre, write := 0, 0 | |
for i := 0; i < len(chars); i++ { | |
if i == len(chars)-1 || chars[pre] != chars[i+1] { | |
chars[write] = chars[pre] | |
write++ | |
count := i - pre + 1 | |
if count > 1 { | |
tempWrite := write | |
for count > 0 { | |
chars[write] = '0' + byte(count%10) | |
count /= 10 | |
write++ | |
} | |
for j := 0; j < (write-tempWrite)/2; j++ { | |
chars[tempWrite+j], chars[write-j-1] = chars[write-j-1], chars[tempWrite+j] | |
} | |
} | |
pre = i + 1 | |
} | |
} | |
return write | |
} |