算法练习-第八天【字符串】

字符串

344.反转字符串

参考:代码随想录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

参考:代码随想录

思考

  1. 本题与344题不同是每2k个步长反转k个字符,既然是固定不长,那么可以使用for循环的时候变量每次增加2k。
  2. 接下来根据题意当要反转的字符数,因为步长是2k,那么只需要在步长内判断当前的i+k是否小于字符串长度即可,如果小于,则反转k个字符。
  3. 反转字符的操作在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.替换空格

参考:代码随想录

思考

  1. 首先统计字符串中空格数
  2. 扩展原字符串的长度,增加空格数乘2
  3. 使用双指针,一个j指向扩展后的字符串末尾,一个i指向原字符串末尾
  4. 移动i,当ss[i] != ''时,将ss[i]的字符移动到ss[j]
  5. 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. 反转字符串中的单词

参考:代码随想录

思考

可以将反转字符串中的单词分成三个步骤:

  1. 使用双指针替换掉字符串中多余的空格
  2. 反转整个字符串的
  3. 反转字符串中的每个单词
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

  1. 反转前n个字符, bacdefg
  2. 反转n到最后的字符, bagfedc
  3. 反转整个字符, 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--
	}
}

总结

  1. 反转字符串主要使用双指针的方式
  2. 如果按照固定的规则一段一段的反转时,可以在for循环的时候处理步长
  3. 反转字符串可以使用先整体反转,再局部反转,比如344.反转字符串中的单词
  4. 反转字符串可以使用先局部反转,再整体反转, 比如剑指 Offer 58 - II. 左旋转字符串
posted @ 2022-09-29 23:56  neil_liu  阅读(31)  评论(0)    收藏  举报