算法练习-第八天【字符串】
字符串
344.反转字符串
思考
题目要求在原地反转字符串,既然是原地反转那么可以第一时间想到双指针,一个指针指向头部,一个指向尾部,互换元素。
func reverseString(s []byte) {
left, right := 0, len(s)-1
for left < right {
s[left], s[right] = s[right], s[left]
left++
right--
}
}
总结
很容易的一道题。
541.反转字符串 II
思考
- 本题与344题不同是每2k个步长反转k个字符,既然是固定不长,那么可以使用for循环的时候变量每次增加2k。
- 接下来根据题意当要反转的字符数,因为步长是2k,那么只需要在步长内判断当前的
i+k
是否小于字符串长度即可,如果小于,则反转k个字符。 - 反转字符的操作在344题做过,可以直接拿来用。
func reverseStr(s string, k int) string {
b := []byte(s)
for i := 0; i < len(b); i += 2 * k {
if i+k < len(b) {
reverseString(b[i : i+k])
} else {
reverseString(b[i:])
}
}
return string(b)
}
func reverseString(s []byte) {
left, right := 0, len(s)-1
for left < right {
s[left], s[right] = s[right], s[left]
left++
right--
}
}
总结
当需要固定规律一段一段去处理字符串的时候,可以尝试使用for循环的表达式上来处理。
剑指Offer 05.替换空格
思考
- 首先统计字符串中空格数
- 扩展原字符串的长度,增加空格数乘2
- 使用双指针,一个
j
指向扩展后的字符串末尾,一个i
指向原字符串末尾 - 移动
i
,当ss[i] != ''
时,将ss[i]
的字符移动到ss[j]
处 - 当
ss[i]==' '
时,将j的位置分别插入02%
,移动i
,j
位置
func replaceSpace(s string) string {
spaceNum := 0
ss := []byte(s)
for i := range ss {
if ss[i] == ' ' {
spaceNum++
}
}
ss = append(ss, make([]byte, 2*spaceNum)...)
i := len(s) - 1
j := len(ss) - 1
for i >= 0 {
if ss[i] != ' ' {
ss[j] = ss[i]
} else {
ss[j] = '0'
ss[j-1] = '2'
ss[j-2] = '%'
j = j - 2
}
i--
j--
}
return string(ss)
}
总结
填充类的问题,首先考虑扩充数组,然后从后向前的方式进行遍历。
151. 反转字符串中的单词
思考
可以将反转字符串中的单词分成三个步骤:
- 使用双指针替换掉字符串中多余的空格
- 反转整个字符串的
- 反转字符串中的每个单词
func reverseWords(s string) string {
ss := removeSpace([]byte(s))
reverseWord(ss)
// 反转每一个单词
start := 0
for i := 0; i <= len(ss); i++ {
// 当ss[i]==' '时,说明一次单词结束,进行反转
if i == len(ss) || ss[i] == ' ' {
reverseWord(ss[start:i])
start = i + 1
}
}
return string(ss)
}
func removeSpace(ss []byte) []byte {
n := len(ss)
// 使用双指针 移除字符数组中的多余空格
slow, fast := 0, 0
// 移除字符串最前面的空格
for n > 0 && ss[fast] == ' ' {
fast++
}
// 移除字符中的空格
for ; fast < n; fast++ {
// 单词间的第一个空格不处理 连续空格直接fast++
if fast-1 > 0 && ss[fast] == ss[fast-1] && ss[fast-1] == ' ' {
continue
}
ss[slow] = ss[fast]
slow++
}
// 移除末尾多余的字符, 经过单词中去空格的逻辑后,此时slow可能会落在最后一个空格上
if slow-1 > 0 && ss[slow-1] == ' ' {
ss = ss[:slow-1]
} else {
ss = ss[:slow]
}
return ss
}
// reverseWord 使用双指针反转列表元素
func reverseWord(ss []byte) {
slow, fast := 0, len(ss)-1
for slow < fast {
ss[slow], ss[fast] = ss[fast], ss[slow]
slow++
fast--
}
}
总结
在使用双指针移除空格时,要记得处理末尾的空格。
剑指 Offer 58 - II. 左旋转字符串
思考
可以通过局部反转+整体转的方式来解决:
s="abcdefg" k=2
- 反转前n个字符,
bacdefg
- 反转n到最后的字符,
bagfedc
- 反转整个字符,
cdefgab
func reverseLeftWords(s string, n int) string {
ss := []byte(s)
// 1. 反转前n个字符
reverseWord(ss[:n])
// 2. 反转n到最后
reverseWord(ss[n:len(ss)])
// 3.反转整个字符串
reverseWord(ss)
return string(ss)
}
func reverseWord(ss []byte) {
left, right := 0, len(ss)-1
for left < right {
ss[left], ss[right] = ss[right], ss[left]
left++
right--
}
}
总结
- 反转字符串主要使用双指针的方式
- 如果按照固定的规则一段一段的反转时,可以在for循环的时候处理步长
- 反转字符串可以使用先整体反转,再局部反转,比如344.反转字符串中的单词
- 反转字符串可以使用先局部反转,再整体反转, 比如剑指 Offer 58 - II. 左旋转字符串