当前位置: 首页 > 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.xdnf.cn/news/1356769.html

相关文章:

  • 【LLIE专题】一种用于低光图像增强的空间自适应光照引导 Transformer(SAIGFormer)框架
  • Ansible 自动化基石:变量定义、优先级控制与 Vault 敏感信息加密实战指南
  • 【重学MySQL】八十七. 触发器管理全攻略:SHOW TRIGGERS与DROP TRIGGER实战详解
  • MySQL管理
  • [身份验证脚手架] 认证路由 | 认证后端控制器与请求
  • MR椎间盘和腰椎分割项目:基于深度学习的医学图像分析
  • 【数据结构】栈和队列——栈
  • MyBatis 和 MyBatis-Plus对比
  • 一个奇怪的问题-Python会替代Java吗?技术语言之争的真相-优雅草卓伊凡
  • 深度学习:CUDA、PyTorch下载安装
  • 用 Bright Data MCP Server 构建实时数据驱动的 AI 情报系统:从市场调研到技术追踪的自动化实战
  • 自由学习记录(87)
  • System.IO.Pipelines 与“零拷贝”:在 .NET 打造高吞吐二进制 RPC
  • 关于 svn无法查看下拉日志提示“要离线”和根目录看日志“no data” 的解决方法
  • 编译Marlin 1.1.9.1固件指南
  • 如何理解“向量”
  • 大数据、hadoop、爬虫、spark项目开发设计之基于数据挖掘的交通流量分析研究
  • 数据挖掘 4.1~4.7 机器学习性能评估参数
  • 【软考架构】云计算相关概念
  • 《CF1120D Power Tree》
  • Implementing Redis in C++ : E(AVL树详解)
  • 深入解析Apache Kafka的核心概念:构建高吞吐分布式流处理平台
  • 自动化运维之k8s——Kubernetes集群部署、pod、service微服务、kubernetes网络通信
  • Linux-函数的使用-编写监控脚本
  • Qt——网络通信(UDP/TCP/HTTP)
  • Linux学习-TCP网络协议
  • Linux shell脚本数值计算与条件执行
  • (计算机网络)JWT三部分及 Signature 作用
  • 如何在 IDEA 中在启动 Spring Boot 项目时加参数
  • [Windows] PDF-XChange Editor Plus官方便携版