旋转数组(三种解决方案)


将数组元素向右移动k个位置,k非负


第一种方案

解决思路:将数组中的元素复制到一个新数组中,将数组元素依次分配到新的位置上
时间复杂度:O(n)
空间复杂度:O(n)

void rotate(int* nums,int numsSize,int k)
{
	k%=numsSize;
	int newArray[numsSize];
	for(int i=0;i<numsSize;i++)
		newArray[i]=nums[i];
	for(int j=0;j<numsSize;j++)
		nums[(j+k)%numsSize]=newArray[j];
}

第二种方案

解决思路:先反转所有的数组元素;再反转前k个数组元素;最后反转剩余的数组元素
时间复杂度:O(n)
空间复杂度:O(1)

void swap(int* x,int* y)
{
	int temp;
	temp=*x;*x=*y;*y=temp;
}
void rotate(int* nums,int numsSize,int k)
{
	k%=numsSize;
	for(int i=0;i<numsSize/2;i++)
		swap(nums+i,nums+numsSize-i-1);
	for(int i=0;i<k/2;i++)
		swap(nums+i,nums+k-i-1);
	for(int i=0;i<(numsSize-k)/2;i++)
		swap(nums+k+i,nums+numsSize-i-1);
}

第三种方案

解决思路:利用一个空间保存数组的第一个元素,计算第一个元素移动后的位置,将该位置上的元素与空间中的元素进行交换,然后继续计算交换后的元素移动后的位置并重复上述操作

举一个例子[1,2,3,4,5,6,7],k=3
利用一个空间temp进行元素之间的交换

(1)temp=1 移动到的位置4 替换后temp=4 [1,2,3,1,5,6,7]
(2)temp=4 移动到的位置7 替换后temp=7 [1,2,3,1,5,6,4]
(3)temp=7 移动到的位置3 替换后temp=3 [1,2,7,1,5,6,4]
(4)temp=3 移动到的位置6 替换后temp=6 [1,2,7,1,5,3,4]
(5)temp=6 移动到的位置2 替换后temp=2 [1,6,7,1,5,3,4]
(6)temp=2 移动到的位置5 替换后temp=5 [1,6,7,1,2,3,4]
(7)temp=5 移动到的位置1 替换后temp=1 [5,6,7,1,2,3,4]

但是这样存在一个隐性的问题,如[1,2,3,4,5,6],k=3

(1)temp=1 移动到的位置4 替换后temp=4 [1,2,3,1,5,6]
(2)temp=4 移动到的位置1 替换后temp=1 [4,2,3,1,5,6]

我们会发现在这种情况下会陷入一个循环(形成了一个圈),在两个数组元素之间不断地变换。这时候就需要我们从第二个元素开始再次进行计算。

通过规律我们可以发现,假设数组元素个数为 n n n,形成的圈数为 x x x,形成的圈遍历元素的个数为 y y y,则有 x n = y k xn=yk xn=yk,所以 x n xn xn n n n, k k k的公倍数。又因为我们希望经过最少的圈就能回到起点,即算法结束,所以 x x x应该尽可能的小。在这种情况下 x n xn xn应为 n n n k k k的最小公倍数,即 x n = l c m ( n , k ) xn=lcm(n,k) xn=lcm(n,k)

x n = l c m ( n , k ) = y k xn=lcm(n,k)=yk xn=lcm(n,k)=yk
y = l c m ( n , k ) / k y=lcm(n,k)/k y=lcm(n,k)/k
一圈我们可以遍历的元素个数为 y y y
所以遍历次数为 n l c m ( n , k ) / k = n k l c m ( n , k ) = g c d ( n , k ) \cfrac{n}{lcm(n,k)/k}=\cfrac{nk}{lcm(n,k)}=gcd(n,k) lcm(n,k)/kn=lcm(n,k)nk=gcd(n,k)
所以遍历的次数为 n n n k k k的最大公约数

int gcd(int x,int y)
{
	return y?gcd(y,x%y):x;
}
void swap(int* x,int* y)
{
	int temp;
	temp=*x;*x=*y;*y=temp;
}
void rotate(int* nums,int numsSize,int k)
{
	k%=numsSize;
	int count=gcd(k,numsSize);
	for(int i=0;i<count;i++){
		int start=i,temp=nums[start];
		do{
		  	int next=(start+k)%numsSize;
		  	swap(&temp,nums+next);
		  	start=next;
		  }while(start!=i);
	}
]

时间复杂度:O(n)
空间复杂度:O(1)

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值