在看编程珠玑时候有这么一题:
将一个长为n的字符串左旋i位,例如abcdefg左旋3位得到:defgabc
在书上提到了两种解法,分别如下,习题中有这么一个问题:i和n的最大公约数如何才能被程序用到?一时间没有思路,看看STL是怎么实现的,果然用到了最大公约数。最后就介绍STL中的rotate算法。
法一:从a[0]开始,每隔i位,将后面的元素移到前面去,将a[i]移到a[0],a[2*i]移到a[i]上,若k*i大于n了,则取模。直到再次遇到a[0]时停止。这时如果还没将所有元素都移动过一遍,则从a[1]开始再次移动。
vector
<
int
> a;
void
rotate(
vector
<
int
>
a
,
int
i
)
{
int
totalmove = 0;
//计算移动的总步数
for
(
int
j = 0; j <
i
; j++) {
int
p = j;
//保存将要被覆盖的点
int
cur = (p +
i
) %
a
.size();
//这一次要移动的点
int
tmp =
a
[j];
//保存第一个元素
while
(cur != j) {
a
[p] =
a
[cur];
p = cur;
cur = (p +
i
) %
a
.size();
totalmove++;
}
a
[p] = tmp;
//将第一个元素放到位置
if
(totalmove ==
a
.size() - 1) {
//因为少一个第一个元素的移动,所以步数减一
break
;
//全部移动过了,停止
}
}
ostream_iterator
<
int
> oit(cout,
" "
);
copy(
a
.begin(),
a
.end(), oit);
cout<<endl;
}
法二:将数组分成两个部分,mn,我们想要达到的目的是nm,则nm = (n^rm^r)^r。
void
reverse(
int
m
,
int
n
)
{
while
(
m
<
n
)
{
int
tmp = a[
m
];
a[
m
] = a[
n
];
a[
n
] = tmp;
m
++,
n
--;
}
}
void
rotate2(
vector
<
int
>
a
,
int
i
)
{
int
r =
i
%
a
.size();
reverse(0,
i
- 1);
//reverse函数的作用是倒转指定区域的元素
reverse(
i
,
a
.size() - 1);
reverse(0,
a
.size() - 1);
}