数组(字符数组)原地循环移位
需求描述
循环移位就是指一个数组假设这个数组的头和尾连接,构成一个圈,每个元素相对自己当前的位置做一个平移。举个例子 左移四位,则左移的结果是 。这算是一个基本的计算机操作,现在相当于从软件的层面实现循环左移。
算法分析
很多人能够发现,移动几位,能够对应将数组分为两个片段,然后将两个片段分别拷贝进数组即可。但是这种方法因为需要进行数组的拷贝,相当于是占用了
级别的空间,但是如果想要这个算法是原地的,就需要寻找其他方法。
原地移位相当于已经是一个固定套路了,这种定义求解方式也是需要平时积累的,出发点是大家先看一个理论,我们假设数组是A,则移动导致数组被划分为两个片段
,这个
和
从何处被分开,我们以左移k位为例(因为是循环移位,右移
位相当于左移
位),而且左移
位和左移
位结果也是一样的,所以只需要讨论
即可。很容易证明,左移k位即从下标为k处划分,
。我们知道移位的结果就是
。
,数组的逆序也满足和转置一样的关系,所以想要得到
可以通过三次转置得到,则结果需要数组进行三次逆序操作,第一次对
逆序,第二次对
逆序,时间复杂度是O(n),此时得到了
,然后再对整个数组逆序,此时得到结果
,这一过程时间复杂度是
。显然数组的逆序是可以在
的时间复杂度下原地完成的,所以几次逆序都是原地的,则空间复杂度是
。整个过程完成原地循环移位,没有增加时间复杂度的量级。
这种思想可以当做定式套路记忆一下,说不定哪天就有算法题遇到了。
reverse函数的代码
void reverse(int array[], int begin, int end)
{
int tmp;
while (begin < end)
{
tmp = array[begin];
array[begin] = array[end];
array[end] = tmp;
begin++;
end--;
}
}
应用举例
牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?
这道题如果要求空间复杂度为 的话,则需要采用字符数组来处理,先对整个字符串进行逆序,然后寻找空格,将字符串划分为单词,然后对单词做一个逆序。