数组循环左移的O(n)&O(1)算法

本文介绍了一种在数据结构考研中高效的算法,用于在一维整数数组中实现循环左移操作,时间复杂度仅为O(n),空间复杂度为O(1)。通过递归拆分和元素交换,适用于n个整数的左移,适用于考研复习和理解数组操作的底层原理。
摘要由CSDN通过智能技术生成

设将n个整数存放到一维数组R中,试设计一个在时间和空间两方面尽可能有效的算法,将R中保有的序列循环左移P(0<P<n)个位置,即将R中的数据由(X0X1……Xn-1)变换为(XpXp+1……Xn-1X0X1……Xp-1)

数据结构考研的题目。网上搜了下,给我看yue了,还是我自己来吧。

这道题目,可以设计出一个时间复杂度为O(n)的非递归原地算法出来,相信时间空间两方面都很难再高效点了。思路如下:

对数组(X0X1……Xn-1)左移p位,我们可以把数组分为((X0X1……Xp-1 | XpXp+1……Xn-1)两部分。

若p<n/2,我们可以选择把(X0X1……Xp-1)和(Xn-pXn-p+1……Xn-1)依次交换,此时数组已经变为(Xn-pXn-p+1……Xn-1 | XpXp+1……Xn-p-1 | X0X1……Xp-1)这三部分。但是最后一部分已经到位了,不需要再操作了,因此需要处理的只有前两部分,即(Xn-pXn-p+1……Xn-1 | XpXp+1……Xn-p-1)这一个小了一截的数组。

诶,那股子“子结构”的感觉是不是出来了?若p>n/2,那就把后面的提到前面即可,操作大差不差。

这个算法抽象来讲,就是一轮一轮地把数组的子串通过元素交换的方式放到它应该的位置,直到换无可换。

下面是代码:

#include <iostream>
#include <algorithm>

using namespace std;

int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };//数组
const int length = 10;//数组长度

//令数组左循环n位

void forth(int lef, int mid, int rig) {//将数组的后(length-n)个元素与前(length-n)个元素依次对调
	int i = lef, j = mid + 1;
	while (j <= rig)
		swap(arr[i++], arr[j++]);
}

void retreat(int lef, int mid, int rig) {//将数组的前n个元素与后n个元素依次对调
	int i = mid, j = rig;
	while (i >=lef)
		swap(arr[i--], arr[j--]);
}

int main() {
	unsigned int n;//左移位数
	cin >> n;
	n %= length;
	int lef = 0, mid = n - 1, rig = length - 1;
	while (mid >= lef && mid < rig) {
		if (mid - lef < rig - mid - 1) {
		//当前需要位移的子串长度小于当前处理的子串长度的一半,就直接把这个子串往后交换
			retreat(lef, mid, rig);
			rig -= (mid - lef + 1);
		}
		else {
		//当前需要位移的子串长度大于当前处理的子串长度的一半,就得把剩下那个小的子串往前交换
			forth(lef, mid, rig);
			lef += (rig - mid);
		}
	}
	for (int i = 0; i < length; ++i)cout << arr[i] << " ";
	cout << endl;
	return 0;
}

每次交换都是旧元素和新元素相交换,没有重复交换的情况,因此时间复杂度为O(n);使用的是原地算法,因此空间复杂度为O(1)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值