要求给出逐个位置移动,且时间复杂度为O(n)的算法
9.写代码环节
问题:给定一个字符串,将后m个字符移到整个字符的前面。例 str = "abcd12" m=2,输出 “12abcd”
①.先写了一个最低级的双重for循环把最后m个字符依次和前面交换换到最前。时间复杂度O(mn)。面试官说需要优化一下
②.继续写了一个临时变量存后m个字符,然后把全部前面的字符从后往前直接覆盖到字符串尾部。时间复杂度O(n),空间复杂度O(m)。面试官说时间复杂度可以但是空间复杂度还不好
③.最后说思路,在m已知的情况下,每个字符的位置是已知的,就比如前面的字符,index为x那么新的字符串中它的index会变为x+m,这样就可以直接把每个字符都放到它们最终的位置,只需要固定的额外内存来存一个字符的备份以及其他变量。
此时时间复杂度O(n),空间复杂度O(1)。
(补充)关于上述两种情况何时出现:
其实是这样的,对于一个长度为 nn 的数组,整体移动 kk 个位置
当 nn 和 kk 的最大公约数 等于 1 的时候:1 次遍历就可以完成交换;比如 n = 5, k = 3n=5,k=3
当 nn 和 kk 的最大公约数 不等于 1 的时候:1 次遍历是无法完成的所有元素归位,需要 mm (最大公约数) 次
所以在最大公约数不为 1 的时候
比如 [A,B,C,D,E,F][A,B,C,D,E,F] 此时 n = 6 \ , k = 4n=6 ,k=4 ,其最大公约数为 22 ,因此需要 22 轮循环
我们就可以把这个数组分成两部分来看:
第 11 轮循环(分组1): A \ E \ C \ [A]A E C [A]
第 22 轮循环(分组2): \ \ \ \ B \ F \ D \ [B] B F D [B]
即:每一轮循环只会在自己的那一组上不停的遍历。所以
数组的前 mm 个元素,其实就是每一个分组的第一个元素,我们控制流程在每次发现一轮循环走到原点时+1
那么如何判断所有的分组都执行归位了呢? 可以有两种方法来控制
第一种:我们就用最大公约数 mm 来控制外循环,代表总共有 mm 轮循环
第二种:由于nn个元素归位需要nn次交换,所以我们定义一个count代表交换次数,当 count = n 时完成