LeetCode 189. 轮转数组

对于这题,一个最直观、最简单的方法是:开一个新数组,将原数组的元素按新顺序填入新数组。

这样会有O(n)O(n)O(n)的空间复杂度。


还有什么办法,能够使空间复杂度降至O(1)O(1)O(1)?

考察一下整个交换过程,可以发现,其可以被拆解为许多"环"交叠在一起。

对任意起点 iii,按 i→i+k→i+2k→...(modn)i → i+k → i+2k → ... (mod n)i→i+k→i+2k→...(modn) 走,迟早回到 iii,形成一个环。如下:

对于 nums = 1, 2, 3, 4, 5, 6, 7, 8, 9, k = 3

令start = 0

首先是 1→4→7→11 \rightarrow 4 \rightarrow 7 \rightarrow 11→4→7→1,发现回到起点,结束这次操作

此时 nums = **7** , 2, 3, **1** , 5, 6, **4** , 8, 9

随后start++

继续操作:2→5→8→22 \rightarrow 5 \rightarrow 8 \rightarrow 22→5→8→2

此时 nums = 7, **8** , 3, 1, **2** , 6, 4, **5** , 9

随后start++

继续操作:3→6→9→33 \rightarrow 6 \rightarrow 9 \rightarrow 33→6→9→3

此时 nums = 7, 8, **9** , 1, 2, **3** , 4, 5, **6**

操作完成

设 g=gcd(n,k)g = gcd(n, k)g=gcd(n,k),则:

环的个数 = ggg,而每个环的长度 = n/gn / gn/g


但除此以外,还有另一种方法。

把数组看成两段拼接 A∣BA | BA∣B:其中 A=nums0..n−k−1A = nums0..n-k-1A=nums0..n−k−1,B=numsn−k..n−1B = numsn-k..n-1B=numsn−k..n−1。

右旋 kkk 位的目标是得到 B∣AB | AB∣A。

用反转的性质:

先整体反转 AB→(AB)R=BRARA B → (A B) ^ R = B ^ R A ^ RAB→(AB)R=BRAR

再反转前 kkk 个(原来的 BRB^RBR)得到 BBB

再反转后 n−kn-kn−k 个(原来的 ARA^RAR)得到 AAA

最终就是 B∣AB | AB∣A。


三种方法的代码如下:

cpp 复制代码
class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        // method 1:
        // int n = nums.size();
        // vector<int> ans(n);
        // for(int i = 0;i<n;i++){
        //     ans[(i + k)%n] = nums[i];
        // }
        // ranges::swap(nums, ans);

        // method 2:
        // int n = nums.size();
        // k = k % n;
        // int g = gcd(n, k);
        // for (int i = 0; i < g; ++i) {
        //     int current = i;
        //     int prev = nums[i];
        //     while (true) {
        //         int next = (current + k) % n;
        //         swap(nums[next], prev);
        //         current = next;
        //         if(current == i) break;
        //     } 
        // }

        // method 3:
        // int n = nums.size();
        // k = k % n;
        // ranges::reverse(nums);
        // reverse(nums.begin(), nums.begin() + k);
        // reverse(nums.begin() + k, nums.end());
    }
};
相关推荐
code2cat3 分钟前
【随笔】RAG语义缓存:问题很相似,答案就能直接复用吗
java·缓存·知识库·rag
Rain的Java大神之路25 分钟前
面了 50 个候选人,90% 都挂在 LeetCode 3 无重复字符的最长子串:滑动窗口的 5 个致命坑
java·后端·leetcode
西凉的悲伤26 分钟前
Jsoup 库 HTML 解析详解
java·前端·html·jsoup
十碗饭吃不饱38 分钟前
Apache POI 踩坑:setFontFamily 二次设置字体不生效、样式残留问题深度解析
java·word·apache
我命由我1234542 分钟前
6-2.Python 异常处理 - 异常捕获(捕获指定异常、常见异常类型、异常信息)
java·运维·开发语言·python·http·https·java-ee
ZhengEnCi1 小时前
一亿条数据取前100条完全指南:从全量排序到分块流式最小堆的4种解法实测
python·算法·排序算法
zaizai10071 小时前
STL深度剖析2
java·c++·算法
数智奔流1 小时前
MiniMax的低价攻势,撞上“背题”疑云
前端·javascript·算法
青少儿编程课堂1 小时前
蓝桥杯·全国青少年信息素养大赛·电子学会Python/C++考级:位运算实战——二进制权限与最大异或解析
c++·python·算法·bfs·信息学竞赛
广州智造1 小时前
Radioss中破坏模型FAILTAB1的详细介绍
数据库·人工智能·算法·机器学习·仿真软件·radioss