编写一个将整数数组旋转给定数k的函数。从结尾开始的k个元素应移到数组的开头,所有其他元素应向右移以留出空间。
旋转应就地完成。
算法的运行时间不能超过O(n),其中n是数组的大小。
此外,必须使用恒定内存来执行该操作。
例如,
如果数组使用元素arr = {1、2、3、4、5、6、7、8、9}初始化
rotation(arr,3)将导致元素为{7,8,9,1,2,2,3,4,5,6}
rotation(arr,6)将得到{4,5,6,7,8,9,1,1,2,3}
编写一个将整数数组旋转给定数k的函数。从结尾开始的k个元素应移到数组的开头,所有其他元素应向右移以留出空间。
旋转应就地完成。
算法的运行时间不能超过O(n),其中n是数组的大小。
此外,必须使用恒定内存来执行该操作。
例如,
如果数组使用元素arr = {1、2、3、4、5、6、7、8、9}初始化
rotation(arr,3)将导致元素为{7,8,9,1,2,2,3,4,5,6}
rotation(arr,6)将得到{4,5,6,7,8,9,1,1,2,3}
Answers:
void reverse(int* a, int* b)
{
while (--b > a) {
*b ^= *a;
*a ^= *b;
*b ^= *a;
++a;
}
}
void rotate(int *arr, int s_arr, int by)
{
reverse(arr, arr+s_arr);
reverse(arr, arr+by);
reverse(arr+by, arr+s_arr);
}
缩小:
v(int*a,int*b){while(--b>a){*b^=*a;*a^=*b;*b^=*a++;}}r(int*a,int s,int y){v(a,a+s);v(a,a+y);v(a+y,a+s);}
a <-- b
¯A⌽B
我不确定APL是否真正需要它,但是在实现中,我已经看到(内部)这将花费与时间成正比的时间A
,并且需要恒定的内存。
{⍵⌽⍨-⍺}
或{⌽⍺⌽⌽⍵}
。在NARS2000中,它可能优雅地写为⌽⍢⌽
。
这是Colin想法的C语言版本。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int gcd(int a, int b) {
int t;
if (a < b) {
t = b; b = a; a = t;
}
while (b != 0) {
t = a%b;
a = b;
b = t;
}
return a;
}
double arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
int s_arr = sizeof(arr)/sizeof(double);
/* We assume 1 <= by < s_arr */
void rotate(double *arr, int s_arr, int by) {
int i, j, f;
int g = gcd(s_arr,by);
int n = s_arr/g;
double t_in, t_out;
for (i=0; i<g; i++) {
f = i;
t_in = arr[f + s_arr - by];
for (j=0; j<n; j++) {
t_out = arr[f];
arr[f] = t_in;
f = (f + by) % s_arr;
t_in = t_out;
}
}
}
void print_arr(double *arr, int s_arr) {
int i;
for (i=0; i<s_arr; i++) printf("%g ",arr[i]);
puts("");
}
int main() {
double *temp_arr = malloc(sizeof(arr));
int i;
for (i=1; i<s_arr; i++) {
memcpy(temp_arr, arr, sizeof(arr));
rotate(temp_arr, s_arr, i);
print_arr(temp_arr, s_arr);
}
}
O(log(n))
操作如何 看by
为1,您的“ j”循环是s_arr / g或N-这是O(N)运算
不确定条件是什么,但是由于我对算法很感兴趣,因此请输入以下内容:
void rotate(int* b, int size, int shift)
{
int *done;
int *p;
int i;
int saved;
int c;
p = b;
done = p;
saved = *p;
for (i = 0; i < size; ++i) {
c = saved;
p += shift;
if (p >= b+size) p -= size;
saved = *p;
*p = c;
if (p == done) {
p += 1;
done = p;
saved = *p;
}
}
}
我也要打高尔夫。126个字节,可以缩短:
void r(int*b,int s,int n){int*d,*p,i,t,c;d=p=b;t=*p;for(i=0;i<s;++i){c=t;p+=n;if(p>=b+s)p-=s;t=*p;*p=c;if(p==d){d=++p;t=*p;}}}
我在这里看不到太多的C ++解决方案,所以我想尝试这种方法,因为它不计算字符数。
这是真正的“就地”旋转,因此使用0的额外空间(从技术上来讲,交换和3个整数除外),并且由于循环正好是N,因此也满足了O(N)的复杂性。
template <class T, size_t N>
void rot(std::array<T,N>& x, int shift)
{
size_t base=0;
size_t cur=0;
for (int i = 0; i < N; ++i)
{
cur=(cur+shift)%N; // figure out where we are going
if (cur==base) // exact multiple so we have to hit the mods when we wrap
{
cur++;
base++;
}
std::swap(x.at(base), x.at(cur)); // use x[base] as holding area
}
}
std::rotate
是因为这样会破坏目的
如果依次轮流执行每个可能的旋转周期n(其中有GCD(n,len(arr))个),则只需要一个数组元素的单个临时副本和几个状态变量。像这样,在Python中:
from fractions import gcd
def rotate(arr, n):
total = len(arr)
cycles = gcd(n, total)
for start in range(0, cycles):
cycle = [i % total for i in range(start, abs(n * total) / cycles, n)]
stash = arr[cycle[-1]]
for j in reversed(range(1, len(cycle))):
arr[cycle[j]] = arr[cycle[j - 1]]
arr[cycle[0]] = stash
cycle
变量的大小不是固定的。您必须随手生成此数组。
C(137个字符)
#include <stdio.h>
void rotate(int * array, int n, int k) {
int todo = (1<<n+1)-1;
int i = 0, j;
int tmp = array[0];
while (todo) {
if (todo & 1<<i) {
j = (i-k+n)%n;
array[i] = todo & 1<<j ? array[j] : tmp;
todo -= 1<<i;
i = j;
} else tmp = array[++i];
}
}
int main() {
int a[] = {1,2,3,4,5,6,7,8,9};
rotate(a, 9, 4);
for (int i=0; i<9;i++) printf("%d ", a[i]);
printf("\n");
}
函数rotate
缩减为137个字符:
void r(int*a,int n,int k){int m=(1<<n+1)-1,i=0,j,t=a[0];while(m)if(m&1<<i){j=(i-k+n)%n;a[i]=(m&1<<j)?a[j]:t;m-=1<<i;i=j;}else t=a[++i];}
Factor具有可旋转数组的内置类型<circular>
,因此实际上是O(1)操作:
: rotate ( circ n -- )
neg swap change-circular-start ;
IN: 1 9 [a,b] <circular> dup 6 rotate >array .
{ 4 5 6 7 8 9 1 2 3 }
IN: 1 9 [a,b] <circular> dup 3 rotate >array .
{ 7 8 9 1 2 3 4 5 6 }
与Ben Voigt令人印象深刻的C解决方案相比,没有那么狡猾的因素:
: rotate ( n s -- )
reverse! swap cut-slice [ reverse! ] bi@ 2drop ;
IN: 7 V{ 0 1 2 3 4 5 6 7 8 9 } [ rotate ] keep .
V{ 3 4 5 6 7 8 9 0 1 2 }
还是去高尔夫,因为我喜欢高尔夫。只要t
<=数组大小,它最大为O(N)。
function r(o,t){for(;t--;)o.unshift(o.pop())}
要处理t
O(N)中的任何比例,可以使用以下内容(称重58个字符):
function r(o,t){for(i=t%o.length;i--;)o.unshift(o.pop())}
不返回,就地编辑数组。
r(o,t) => rot
/_(( \d+)+)( \d+)/$3$1
输入:k用_
一个数字表示为一元整数,后跟一个空格,然后是一个以空格分隔的整数数组。
输出:一个空格,然后旋转数组。
例:
___ 1 2 3 4 5/_(( \d+)+)( \d+)/$3$1
最终状态:
3 4 5 1 2
说明:
在每次迭代中,它取代一个_
和阵列[array] + tail
与tail + [array]
。
例:
___ 1 2 3 4 5
__ 5 1 2 3 4
_ 4 5 1 2 3
3 4 5 1 2
O(n)
,然后执行n
一次。
public static void rotate(int[] arr, int by) {
int n = arr.length;
int i = 0;
int j = 0;
while (i < n) {
int k = j;
int value = arr[k];
do {
k = (k + by) % n;
int tmp = arr[k];
arr[k] = value;
value = tmp;
i++;
} while (k != j);
j++;
}
}
演示在这里。
精简Java脚本114:
function rotate(e,r){n=e.length;i=0;j=0;while(i<n){k=j;v=e[k];do{k=(k+r)%n;t=e[k];e[k]=v;v=t;i++}while(k!=j);j++}}
def rotate(a, n): a[:n], a[n:] = a[-n:], a[:-n]
蟒蛇
import copy
def rotate(a, r):
c=copy.copy(a);b=[]
for i in range(len(a)-r): b.append(a[r+i]);c.pop();return b+c
def r(a,n): return a[n:]+a[:n]
有人可以检查一下是否确实符合要求吗?我认为可以,但是还没有研究CS。
将最后k个元素与前k个元素交换,然后将其余元素旋转k个。如果最后剩余的元素少于k个,则将它们旋转剩余元素的k%数量。我认为以上没有人采用这种方法。对每个元素仅执行一个交换操作,将所有操作都放在适当的位置。
public void rotate(int[] nums, int k) {
k = k % nums.length; // If k > n, reformulate
rotate(nums, 0, k);
}
private void rotate(int[] nums, int start, int k) {
if (k > 0) {
if (nums.length - start > k) {
for (int i = 0; i < k; i++) {
int end = nums.length - k + i;
int temp = nums[start + i];
nums[start + i] = nums[end];
nums[end] = temp;
}
rotate(nums, start + k, k);
} else {
rotate(nums, start, k % (nums.length - start));
}
}
}