字符串旋转 不同解法

项目github地址:bitcarmanlee easy-algorithm-interview-and-practice
欢迎大家star,留言,一起学习进步

本博主被问到一个这样的问题:
给定一个字符串"abcdefg",要求把字符串前面的若干个字符,比如3个字符,即"abc"移动到字符串的末尾,最后的字符串变为"defgabc"。

解法一

玩数据的同学习惯用python,如果用python的话,这个问题自然没有太多技术含量,分分钟搞定的节奏。因为python处理各种字符串的方便程度,实在是令你想不到用其他方式去解决。

def invert_str(n):
    raw_str = "abcdefg"
    ret_str = raw_str[n:] + raw_str[0:n]
    print "ret_str is: " + ret_str

invert_str(3)

结果为:

ret_str is: defgabc

利用python里的字符串切片,确实实现起来很简单。但是如果是作为一个算法题考察的话,这种代码显然是不符合要求的。so,从时间复杂度与空间复杂度的角度再考虑这个问题。

解法二 空间复杂度小

如果要求空间复杂度比较小,可以用下面的解法。每次将需要移动的字符一个一个移动到字符串的尾部,so code如下

def leftShitMethod(list_str,n):
    tmp = list_str[0]
    #注意是从1开始,而不是0
    for i in xrange(1,n):
        list_str[i-1] = list_str[i]
    list_str[n-1] = tmp
    
def violenceMethod(m):
    raw_str = "abcdefg"
    list_str = list(raw_str)
    length = len(list_str)
    while m:
        leftShitMethod(list_str, length)
        m -= 1
    ret_str = "".join(list_str)
    print "now ret_str is: ",ret_str

violenceMethod(3) 

代码运行结果

now ret_str is:  defgabc

leftShitMethod方法是每次将第一个字符移到字符串最后,每次移动的的复杂度为O(n)。移动m个字符的话,总复杂度为O(n*m)。空间复杂度为O(1),只开辟了一个tmp单元存储第一个字符。

有没有时间复杂度更低的方法勒

3.时间复杂度更低的方式

如果我们将一个字符串分成 X X X Y Y Y两部分 ,做如下定义:
假设 X = " a b c " X="abc" X="abc" X T = " b c a " X^T = "bca" XT="bca",则
( X T Y T ) T = Y X (X^TY^T)^T=YX (XTYT)T=YX
看到这个式子同学们想到了什么,对嘛,跟矩阵的转置是一样一样的嘛。
例如,源字符串为"abcdefg",将"abc"移到末尾
X = " a b c " X="abc" X="abc", Y = d e f g Y=defg Y=defg, X T = " c b a " X^T="cba" XT="cba", Y T = g f e d Y^T=gfed YT=gfed, X T Y T = d e f g a b c X^TY^T=defgabc XTYT=defgabc

原理解释到此,接下来看代码

def swap_char(list_str,begin,end):
    while begin < end:
        list_str[begin],list_str[end] = list_str[end],list_str[begin]
        begin += 1
        end -= 1
        
def invert_str_recursive(n):
    raw_str = "abcdefg"
    list_str = list(raw_str)
    length = len(raw_str)
    swap_char(list_str,0,n-1) #反转前面的部分
    swap_char(list_str,n,length-1) #反转后面的部分
    swap_char(list_str,0,length-1) #反转整个部分
    ret_str = "".join(list_str)
    print "ret_str is: ",ret_str

invert_str_recursive(3)

代码运行结果

ret_str is:  defgabc

可以看出,此方法的时间复杂度为O(n),空间复杂度为O(1)!

4.变形一

编写程序,在原字符串中把字符串尾部的m个字符移动到字符串的头部。例如:
输入为"Ilovecoding",将尾部6个字符移到前面,则输出为"codingIlove"

def swap_char(list_str,begin,end):
    while begin < end:
        list_str[begin],list_str[end] = list_str[end],list_str[begin]
        begin += 1
        end -= 1

def invert_back(n):
    raw_str = "Ilovecoding"
    list_str = list(raw_str)
    length = len(list_str)
    swap_char(list_str,0,length-n-1)
    swap_char(list_str,length-n,length - 1)
    swap_char(list_str,0,length-1)
    ret_str = "".join(list_str)
    print "ret_str is: ",ret_str

invert_back(6)

运行结果

ret_str is:  codingIlove

5.变形2

题目:输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。句子中单词以空格符隔开。为简单起见,标点符号和普通字母一样处理。
例如:输入"I’m like coding.",输出"coding. like I’m"

def swap_char(list_str,begin,end):
    while begin < end:
        list_str[begin],list_str[end] = list_str[end],list_str[begin]
        begin += 1
        end -= 1

def invert_word():
    raw_sentence = "I'm like coding."
    list_str = list(raw_sentence)
    swap_char(list_str,0,len(raw_sentence)-1)
    
    tmp_each_word = []
    ret = ""
    
    for i in xrange(len(list_str)):
        if list_str[i] != " ":
            tmp_each_word.append(list_str[i])
        else:
            swap_char(tmp_each_word,0,len(tmp_each_word)-1)
            ret += "".join(tmp_each_word)
            ret += " "
            tmp_each_word = []
        #处理最后一个单词
        if i == len(list_str)-1:
            swap_char(tmp_each_word,0,len(tmp_each_word)-1)
            ret += "".join(tmp_each_word)
    
    print "ret is: ",ret

结果

ret is:  coding. like I'm

我们先颠倒句子中的所有字符。这时,不但翻转了句子中单词的顺序,而且单词内字符也被翻转了。我们再颠倒每个单词内的字符。由于单词内的字符被翻转两次,因此顺序仍然和输入时的顺序保持一致。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值