当前位置: 首页 > news >正文

leetcode_189 轮转数组

1. 题意

给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。

2. 题解

2.1 开一个数组

由于我比较笨比,所以只能想到这种办法。

当前位置为iii,那么它将移动到(i+k)%n(i+k)\%n(i+k)%n的位置上去。

class Solution {
public:void rotate(vector<int>& nums, int k) {int n = nums.size();vector<int> tmp = nums;for (int i = 0;i < n; ++i) {tmp[ (i + k) % n] = nums[i];}nums = tmp;}
};

除此之外,我还能想到的就是,既然是向右移kkk位,那么实际上相当于

把最后的kkk位的数给移动到前面来,而这也是反转法的一个前提,不过

我没有想到反转的这一做法,而是直接这样移动。因此空间复杂度仍然是O(n)O(n)O(n)

class Solution {
public:void rotate(vector<int>& nums, int k) {int n = nums.size();k %= n;if ( k ) {for (int i = 0; i < n - k; ++i) {nums.emplace_back( nums[i]);}nums.erase(nums.begin(), nums.begin() + n - k);}}
};

要注意的一点是kkk城对nnn取余。

2.2 环状替换

这个其实是比较数学的做法,涉及到最大公约数最小公倍数。

对于0→n−10\to n-10n1任意一个位置来说,它每次可以跳kkk步,

它最少需要跳几次才能回到原来的位置呢?

我们假设需要跳bbb次,同时假设跳了aaa圈,那么我们容易得到

an=bkan=bk an=bk

我们知道n∣ann \mid annank∣ank \mid ankan,也就是ananan同时是n,kn,kn,k的倍数,那么

必然有lcm(n,k)∣anlcm(n,k) \mid anlcm(n,k)an,由于要尽可能的让ananan小,

因此an=lcm(n,k)an=lcm(n,k)an=lcm(n,k)

进而我们可以得到

b=lcm(n,k)kb=\frac{lcm(n,k)}{k} b=klcm(n,k)

根据最大公因数和最小公倍数之间的关系
nkgcd⁡(n,k)=lcm(n,k)\frac{nk}{\gcd(n,k)}=\mathop{lcm}(n,k) gcd(n,k)nk=lcm(n,k)
代入得到
b=ngcd⁡(n,k)b=\frac{n}{\gcd(n,k)} b=gcd(n,k)n

由于一个位置需要跳bbb次才能回到原来位置,又因为这是个环所以

跳跃的次数就是这个环的元素个数。一个环有b=ngcd⁡(n,k)b=\frac{n}{\gcd(n,k)}b=gcd(n,k)n

元素,因此环的个数就是nb=gcd⁡(n,k)\frac{n}{b}=\gcd(n,k)bn=gcd(n,k)。这个环的个数也就是

代码中的countcountcount

class Solution {
public:int gcd(int a, int b) {return b == 0 ? a : gcd( b, a % b);}void rotate(vector<int>& nums, int k) {int n = nums.size();k %= n;int cnt = gcd(n, k);for (int i = 0;i < cnt; ++i) {int st = i;for (int j = 1;j  < n / cnt; ++j) {int next_pos = (st + j * k) % n;std::swap( nums[st], nums[next_pos]);}}}
};

还有一个问题,当startstartstart所在的环遍历完了之后,

为什么start+1start+1start+1就是下一个环了呢?

startstartstart所在环不会已经遍历过start+1start+1start+1这个位置了吗?

我们假设存在这样一种情况,那么必然有
start+mk≡start+1(modn)mk≡1(modn)start +mk \equiv start+1 \quad (\ \bmod\ n)\\ mk\equiv 1 \quad (\ \bmod \ n) start+mkstart+1( mod n)mk1( mod n)

那么gcd⁡(n,k)=1\gcd(n,k)=1gcd(n,k)=1,而这与start+1start+1start+1的存在性是矛盾的。

因此不会存在这种情况。

2.3 反转数组

+++表示数组的拼接操作,

R(Arr)R(Arr)R(Arr)表示将数组反转这一操作。

我们容易得到

R(A+B)=R(B)+R(A)R(R(A))=AR(A+B)=R(B)+R(A)\\ R(R(A)) =A R(A+B)=R(B)+R(A)R(R(A))=A

这两种性质

对于循环右移kkk位这种操作,实际上可以通过反转来实现。

我们令AAA 表示numsnumsnums中的前n−kn-knk个数依次序组成的数组,

BBB表示numsnumsnums中后kkk个数依次组成的数组。

实际上我们就是要通过反转将

A+B→B+AA+B \to B+AA+BB+A

根据上面的性质,我们可以很容易的通过三次反转得到最终的结果。

class Solution {
public:void rotate(vector<int>& nums, int k) {int n = nums.size();k %= n;reverse(nums.begin(), nums.end());reverse(nums.begin(), nums.begin() + k);reverse(nums.begin() + k, nums.end());}
};

时间复杂度O(2n)=O(n)O(2n)=O(n)O(2n)=O(n)

空间复杂度O(1)O(1)O(1)

3. 参考

0x3f
leetcode

http://www.dtcms.com/a/349166.html

相关文章:

  • 什么嵌入式接入大模型:第二篇基于 STM32 ESP32 的社会服务助手
  • AI重塑跨境电商:选品成功率提升53%+物流效率加快34%,多语种运营成破局关键
  • String的intern方法
  • 数据库服务优化设置
  • nano命令使用方法
  • 备考NCRE三级信息安全技术 --- L1 信息安全保障概述
  • 自编 C# 颜色命名和色彩显示,使用 DataGridView 展示颜色命名、RGB值
  • 推进数据成熟度旅程的 3 个步骤
  • 基于 MATLAB 的信号处理实战:滤波、傅里叶变换与频谱分析
  • 什么是IP代理
  • 智慧农业病虫害监测误报率↓82%!陌讯多模态融合算法实战解析
  • 基于微信小程序校园微店源码
  • 电力电子simulink练习10:反激Flyback电路搭建
  • [leetcode] - 不定长滑动窗口
  • 深度学习卷积神经网络项目实战
  • 电容触控:自电容 vs 互电容
  • Rust 登堂 生命周期(一)
  • 内网后渗透攻击--域控制器安全(1)
  • 控制启动过程
  • 【typenum】 25 去除无符号整数前导零的特性(private.rs片段)
  • 重塑招聘战场:AI得贤招聘官AI面试智能体6.3如何用“精准”重新定义人才筛选?
  • C++(String):
  • 2025 年 8 月 22 日科技前沿:技术突破与范式跃迁的交汇点
  • golang1 专栏导学
  • 算法题(190):食物链(带权并查集)
  • leetcode 162 寻找峰值
  • 1、vue2面试题--生命周期
  • Goang开源库之go-circuitbreaker
  • HTTP请求中的CGI请求与登录注册机制
  • AI大模型企业落地指南-笔记01