题目描述
给定一个字符串,要求把字符串前面的若干个字符移动到字符串的尾部,如把字符串“abcdef”前面的2个字符'a'和'b'移动到字符串的尾部,使得原字符串变成字符串“cdefab”。请写一个函数完成此功能,要求对长度为n的字符串操作的时间复杂度为 O(n),空间复杂度为 O(1)。
分析与解法
三步反转法:
例如,字符串 abcdef ,若要让def翻转到abc的前头,只要按照下述3个步骤操作即可:
- 首先将原字符串分为两个部分,即X:abc,Y:def;
- 将X反转,X->X^T,即得:abc->cba;将Y反转,Y->Y^T,即得:def->fed。
- 反转上述步骤得到的结果字符串X^TY^T,即反转字符串cbafed的两部分(cba和fed)给予反转,cbafed得到defabc,形式化表示为(X^TY^T)^T=YX,这就实现了整个反转。
package main
import "fmt"
func ReverseString(runes []rune) {
for from, to := 0, len(runes)-1; from < to; from, to = from+1, to-1 {
runes[from], runes[to] = runes[to], runes[from]
}
}
func LeftRotateString(runes []rune, m int) {
m %= len(runes)
ReverseString(runes[:m]) // 一次反转
ReverseString(runes[m:]) // 二次反转
ReverseString(runes) // 三次反转
}
func main() {
runes := []rune("abcdef")
LeftRotateString(runes, 3)
fmt.Println(string(runes))
}
举一反三
1、链表翻转。给出一个链表和一个数k,比如,链表为1→2→3→4→5→6,k=2,则翻转后2→1→6→5→4→3,若k=3,翻转后3→2→1→6→5→4,若k=4,翻转后4→3→2→1→6→5,用程序实现。
package main
import "fmt"
type Node struct {
Val int
Next *Node
}
// 递归翻转链表
func revseseLinkList(head *Node) *Node {
if head == nil || head.Next == nil {
return head
} else {
newHead := revseseLinkList(head.Next)
head.Next.Next = head
head.Next = nil
return newHead
}
}
// 按照 K 拆分链表
func splitByK(head *Node, k int) (head1, head2 *Node) {
head1, p := head, head
for i := 0; i < k-1; i++ {
p = p.Next
}
head2 = p.Next
p.Next = nil
return
}
func reverseK(head *Node, k int) *Node {
oldHead := head
head1, head2 := splitByK(head, k) // 拆分为前后两个链表
newHead1 := revseseLinkList(head1) // 翻转一次(前半部分)
newHead2 := revseseLinkList(head2) // 翻转二次(后半部分)
oldHead.Next = newHead2 // 合并
return newHead1
}
func main() {
head := &Node{1, nil}
n2 := &Node{2, nil}
n3 := &Node{3, nil}
n4 := &Node{4, nil}
n5 := &Node{5, nil}
n6 := &Node{6, nil}
head.Next = n2
n2.Next = n3
n3.Next = n4
n4.Next = n5
n5.Next = n6
h := reverseK(head, 3)
for h != nil {
fmt.Printf("%d ", h.Val)
h = h.Next
}
}
2、编写程序,在原字符串中把字符串尾部的m个字符移动到字符串的头部,要求:长度为n的字符串操作时间复杂度为O(n),空间复杂度为O(1)。 例如,原字符串为”Ilovebaofeng”,m=7,输出结果为:”baofengIlove”。
package main
import "fmt"
func ReverseString(runes []rune) {
for from, to := 0, len(runes)-1; from < to; from, to = from+1, to-1 {
runes[from], runes[to] = runes[to], runes[from]
}
}
func RightRotateString(runes []rune, m int) {
m %= len(runes)
m = len(runes) - m // 转成成普通旋转
ReverseString(runes[:m]) // 一次反转
ReverseString(runes[m:]) // 二次反转
ReverseString(runes) // 三次反转
}
func main() {
runes := []rune("Ilovebaofeng")
RightRotateString(runes, 7)
fmt.Println(string(runes))
}
3、单词翻转。输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变,句子中单词以空格符隔开。为简单起见,标点符号和普通字母一样处理。例如,输入“I am a student.”,则输出“student. a am I”。
package main
import "fmt"
func ReverseString(runes []rune) {
for from, to := 0, len(runes)-1; from < to; from, to = from+1, to-1 {
runes[from], runes[to] = runes[to], runes[from]
}
}
func ReverseWord(runes []rune) {
ReverseString(runes) // 整体翻转
begin := 0
for i := 0; i < len(runes); i++ {
if string(runes[i]) == " " {
ReverseString(runes[begin:i]) // 分别翻转每个单词
begin = i + 1
}
}
}
func main() {
runes := []rune("I am a student.")
ReverseWord(runes)
fmt.Println(string(runes))
}