旋转字符串

题目描述

给定一个字符串,要求把字符串前面的若干个字符移动到字符串的尾部,如把字符串“abcdef”前面的2个字符'a'和'b'移动到字符串的尾部,使得原字符串变成字符串“cdefab”。请写一个函数完成此功能,要求对长度为n的字符串操作的时间复杂度为 O(n),空间复杂度为 O(1)。

分析与解法

三步反转法:

例如,字符串 abcdef ,若要让def翻转到abc的前头,只要按照下述3个步骤操作即可:

  1. 首先将原字符串分为两个部分,即X:abc,Y:def;
  2. 将X反转,X->X^T,即得:abc->cba;将Y反转,Y->Y^T,即得:def->fed。
  3. 反转上述步骤得到的结果字符串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))
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值