开始的话:
每天三道题,养成良好的思维习惯。
一位爱生活爱技术来自火星的程序汪
这个题是什么意思呢?就是给定一组字符串比如: ′ a b c d e f g ′ 'abcdefg ' ′abcdefg′,要求将前 3 3 3个字母移动到字符串的后面去,也就是会得到 ′ d e f g a b c ′ 'defgabc' ′defgabc′。是不是很简单,很好理解。
做了一些算法题之后(本来准备说做了很多算法题的,后来想了一下和一些大佬们动不动就刷了 300 − 400 300-400 300−400的相比都不好意思开口),很重要的一件事情就是将问题简单化,由易到难,分治等这些思想尤为关键。不要直接上来就想一步到位(这些只有那些你看不懂他算法代码的家伙才能做到吧,也是一个不断积累的过程。),慢慢来,谁让我比较笨呢!
o k ok ok, 开始吧!
迭代
和描述中所述一次移动三个似乎有很多数组移动的情况,好像很不好一下就想到怎么去很优雅的写出来(发现自己进入了一个误区,每次总是想很优雅的直接写出代码,最后才发现是慢慢改动代码才优雅的,果然还是要一步一步来,不能心急。)。那就简单来吧!三个不行我们就只移动一个好吧:就是把字符串中第一个字符 a a a移动到字符串末尾 ′ b c d e f g a ′ 'bcdefga ' ′bcdefga′,这个还是比较好做的对吧,一个一个向前替换,需要单独记录第一个字符。话不多说上代码:
def rotate(s: list, length: int):
"""
反转一个字符
:param s: 输入字符串数组
:param length: 字符串长度
"""
first = s[0]
for i in range(1, length):
# 从第二个开始逐一替换掉前一个的值
s[i - 1] = s[i]
# 给第一个值赋值到最后下标位置
s[length - 1] = first
s o so so e a s y easy easy 吧,那么反转三个呢?是不是就很简单了,让上面的循环三次就好了,哈哈,我真聪明!
for i in range(3):
rotate(s, 7)
print(s)
但是呢,这并没有完,做算法题最重要的是什么?没错就是 时间复杂度 和 空间复杂度 的分析。对于上面这样的做法,这两个指标分别是多少呢?
时间复杂度 ->
O
(
n
∗
m
)
O(n*m)
O(n∗m)
n
n
n就表示前几个字符需要反转。
m
m
m就是字符串数组的长度了。
空间复杂度 ->
O
(
1
)
O(1)
O(1) 只存储了一个变量
f
i
r
s
t
first
first。
对于空间复杂度还是很满意的,但是时间复杂度就似乎有点高了,每次都遍历了整个数组,这还是很恐怖的。
那是否有更快点的方法呢?那肯定是有的。
分治
和我之前讲的一样,先简单化:我们一个一个移动,再移动整体,问题是可以解决的对吧,没大量实践经验支撑的时候,我们就要这样从简到繁从易到难的过程,这个真的很重要,思维也是逐步养成的。那么怎么优化呢?知道 归并排序 和 快速排序 的小伙伴肯定是知道 分治思想 的(这个思想其实也是有一种从简单出发解决复杂问题,只是有时候这种所谓的简单不好抽象出来。都是艺术 哈哈。),所以我们这个问题也是可以运用 分治思想 的。
怎么分?很自然的,要反转的那一部分作为一部分,剩下的作为另外一部分。如果我们能把这两部分分别反转了,然后合并之后再反转,是不是就解决我们这个问题了呢!
和之前的 归并排序 和 快速排序 一样先写公式:
rotate(rotate(first_part) + rotate(second_part))
还拿上面的列子: ′ a b c d e f ′ 'abcdef' ′abcdef′,短一点方便说明。还是前三个反转。
first_part = 'abc'
second_part = 'def'
rotate(first_part) = 'cba'
rotate(second_part ) = 'fed'
sum = rotate(first_part) + rotate(second_part ) = 'cbafed'
rotate(sum) = 'defabc'
上面过程很清晰明了了吧! 我们只需要最后一次循环的时候遍历整个数组,而之前两次迭代都是数组的一部分。是一次的累加所以时间复杂度是
O
(
m
)
O(m)
O(m),空间复杂度也是
O
(
1
)
O(1)
O(1)。
r
o
t
a
t
e
rotate
rotate方法如下:
def rotate(s: list, start: int, end: int) -> list:
while start < end:
# 互换位置
s[start], s[end] = s[end], s[start]
start += 1
end -= 1
s = list('abcdefg')
length = len(s)
# 移动前三个
m = 3
# m > length 的时候等价
m %= length
rotate(s, 0, m - 1)
rotate(s, m, length - 1)
rotate(s, 0, length - 1)
print(s)