旋转数组的三种解法

简介: 本题为数组旋转问题,要求将数组向右循环移动k次。直接模拟会超时,故采用三种优化方法:一、额外数组法,时间空间复杂度均为O(n);二、环状替换,通过最大公约数计算遍历次数,空间复杂度O(1);三、数组翻转,先整体翻转再分段翻转,实现高效原地旋转。


前提概要与题目分析

这道题的基础思路类似于字符串左旋,即先把数组最后一个元素存起来,所有前numsSize-1个元素向后移一次(从后往前)

代码如下:

void rotate(int* nums, int numsSize, int k) {
int tmp=0;
k%=numsSize;
for(int i=0;i=0;j--)
{
nums[j+1]=nums[j];
}
nums[0]=tmp;
}
}
但是这个方法有个严重的问题是当数组元素和循环次数多了后会超出规定的时间限制

因此需要改变一下思路:

方法一:使用额外的数组
我们可以使用额外的数组来将每个元素放至正确的位置。用 n 表示数组的长度,我们遍历原数组,将原数组下标为 i 的元素放至新数组下标为 (i+k) 的位置,最后将新数组拷贝至原数组即可。

void rotate(int* nums, int numsSize, int k) {
int newnums[numsSize];
for(int i=0;i<numsSize;i++)
{
newnums[(k+i)%numsSize]=nums[i];
}
for(int i=0;i<numsSize;i++)
{
nums[i]=newnums[i];//拷贝数组
}
}
这里的时间复杂度和空间复杂度都是O(n)(n是数组长度)

方法二:环状替换
以上的公式推导为下面的代码作为铺垫

方法分析:

在这个方法中采用了在原数组的基础上进行位置更新的方法以避免额外开辟新的数组浪费空间,操作方法是从数组首元素开始,将首元素current拷贝到tmp临时变量中,然后跳跃k个元素,将第k个元素和tmp交换,后第k个元素作为current继续拷贝跳跃交换,不断循环直到current回到首元素,以上算遍历一次。

关于遍历的次数,用到了数学公式推导,由公式:

a(回到current所用的圈数)×n(数组元素个数)=b(一次遍历的元素个数)×k(旋转个数/跳过元素个数)

可知:an是n的倍数,an=bk也是k的倍数,因此an是n和k的公倍数(为了将未知量用已知量n,k表示)

由于遍历至current回到原点就结束,因此a要为最小圈数,an就是n,k的最小公倍数,即b=lcm(n,k)/k,所以遍历的次数就是n/b即nk/lcm(n,k)(两数相乘除以两数的最小公倍数=两数的最大公约数)因此求遍历的次数就是求n和k的最大公约数。

另外每个元素只会被遍历一次。

代码如下:

int gcd(int a, int b) {
return b ? gcd(b, a % b) : a;
}

void swap(int a, int b) {
int t = a; a = b, b = t;
}

void rotate(int* nums, int numsSize, int k) {
k = k % numsSize;
int count = gcd(k, numsSize);//求最大公约数
for (int start = 0; start < count; ++start) {
int current = start;
int prev = nums[start];
do {
int next = (current + k) % numsSize;
swap(&nums[next], &prev);
current = next;
} while (start != current);
}
}
如果无法理解公式推导可使用单独的变量 count 跟踪当前已经访问的元素数量,当 count=n 时,结束遍历过程。

int gcd(int a,int b)
{
return b?gcd(b,a%b):a;
}

void swap(int a, int b) {
int t = a; a = b, b = t;
}

void rotate(int* nums, int numsSize, int k)
{
k%=numsSize;
int count=0;
int start=0;
while(count<numsSize)
{
int current=start;
int prev=nums[start];
do{
int next=(current+k)%numsSize;
swap(&prev,&nums[next]);
current=next;
count++;
}while(start!=current);
start++;
}
}

方法三:数组翻转
该方法基于如下的事实:当我们将数组的元素向右移动 k 次后,尾部 k%n 个元素会移动至数组头部,其余元素向后移动 k%n 个位置。

该方法为数组的翻转:我们可以先将所有元素翻转,这样尾部的 k%n 个元素就被移至数组头部,然后我们再翻转 [0,k%(n−1)] 区间的元素和 [k%n,n−1] 区间的元素即能得到最后的答案。

void swap(int a, int b) {
int t = a; a = b, b = t;
}

void reverse(int* nums, int start, int end) {
while (start < end) {
swap(&nums[start], &nums[end]);
start += 1;
end -= 1;
}
}

void rotate(int* nums, int numsSize, int k) {
k %= numsSize;
reverse(nums, 0, numsSize - 1);
reverse(nums, 0, k - 1);
reverse(nums, k, numsSize - 1);
}

另外如果是字符串的话还可以用stract函数做拼接实现旋转

相关文章
|
3月前
|
算法 数据挖掘 BI
拼多多 API 接口:解锁电商世界的无限可能
拼多多API接口是商家高效运营的利器,支持商品信息同步、订单自动化管理、营销活动对接及数据决策分析。通过API,可实现多平台信息互通、提升运营效率30%、降低错误率20%,助力销量增长50%。掌握API,赢在电商竞争起跑线。
410 5
|
3月前
|
机器学习/深度学习 人工智能 PyTorch
PyTorch深度学习 ? 带你从入门到精通!!!
🌟 蒋星熠Jaxonic,深度学习探索者。三年深耕PyTorch,从基础到部署,分享模型构建、GPU加速、TorchScript优化及PyTorch 2.0新特性,助力AI开发者高效进阶。
PyTorch深度学习 ? 带你从入门到精通!!!
|
4月前
|
存储 监控 数据可视化
大模型可观测1-5-10:发现、定位、恢复的三层能力建设
本文通过丰富的代码Demo和截图为读者提供了可落地的实践指南。
708 34
大模型可观测1-5-10:发现、定位、恢复的三层能力建设
|
3月前
|
机器学习/深度学习 PyTorch TensorFlow
TensorFlow与PyTorch深度对比分析:从基础原理到实战选择的完整指南
蒋星熠Jaxonic,深度学习探索者。本文深度对比TensorFlow与PyTorch架构、性能、生态及应用场景,剖析技术选型关键,助力开发者在二进制星河中驾驭AI未来。
730 13
|
3月前
|
C++
基本二叉树与排序二叉树(C++源码)
本程序实现二叉树基本操作与二叉排序树应用。支持前序建树、四种遍历、求深度、叶子数、第K层节点数及查找功能;并实现二叉排序树的构建、中序输出与查找比较次数统计,分析不同插入顺序对树形态和查找效率的影响。
|
3月前
|
机器学习/深度学习 算法 C++
【DFS/回溯算法】2016年蓝桥杯真题之路径之谜详解
题目要求根据城堡北墙和西墙箭靶上的箭数,推断骑士从西北角到东南角的唯一路径。每步移动时向正北和正西各射一箭,同一格不重复经过。通过DFS回溯模拟“拔箭”过程,验证路径合法性。已知箭数约束路径唯一,最终按编号输出行走顺序。
|
3月前
|
存储 消息中间件 监控
MySQL 到 ClickHouse 明细分析链路改造:数据校验、补偿与延迟治理
蒋星熠Jaxonic,数据领域技术深耕者。擅长MySQL到ClickHouse链路改造,精通实时同步、数据校验与延迟治理,致力于构建高性能、高一致性的数据架构体系。
MySQL 到 ClickHouse 明细分析链路改造:数据校验、补偿与延迟治理
|
3月前
|
缓存 前端开发 NoSQL
《CRM性能突围:从4秒卡顿到毫秒级响 应的全链路实战拆解》
本文记录了企业级CRM系统从4秒卡顿到毫秒级响应的全链路性能优化实战。系统因业务扩张(200人销售团队、300万条客户数据)出现查询超时、数据库高负载等问题,团队跳出“通用方案”陷阱,分阶段突破:数据层通过精准索引、“年+季度”分表、预计算宽表优化,将SQL耗时从3.5秒压至200毫秒;缓存层搭建“本地缓存(Caffeine)+分布式缓存(Redis)”架构,结合热点隔离与Binlog监听保证一致性,缓存命中率提升至91%;应用层通过异步解耦(消息队列)、资源隔离(微服务拆分)、前端配合优化,解决阻塞与资源争抢。最终通过全链路监控与定期迭代,构建长效优化机制。
298 9
|
3月前
|
NoSQL 数据库 Redis
《微服务幂等性踩坑实录:从资损到全链路零故障的7个关键突破》
本文记录了团队因微服务接口缺乏幂等设计,在电商大促中因重复支付回调导致资损后,重构全链路幂等方案的实战经历。团队曾陷入三大误区:迷信“唯一ID+数据库唯一索引”,却因分布式ID重复、数据库锁阻塞在高并发下失效;忽略业务状态流转,导致重复请求触发库存超卖;过度依赖粗粒度分布式锁,因锁过期、误释放引发订单阻塞。最终通过“精准锁Key+锁续期+归属校验”“业务状态白名单+数据库行锁”等方案解决问题,核心结论为:幂等设计不是依赖单一工具,而是技术方案与业务逻辑的深度融合。
202 9
|
3月前
|
机器学习/深度学习 PyTorch TensorFlow
卷积神经网络深度解析:从基础原理到实战应用的完整指南
蒋星熠Jaxonic,深度学习探索者。深耕TensorFlow与PyTorch,分享框架对比、性能优化与实战经验,助力技术进阶。