6,2,[1,2,3,4,5,6]返回值:
[5,6,1,2,3,4]
(1<=N<=100,M>=0) 解法1: 对数组中元素进行遍历,遍历过程中将每个元素直接移动至应在的位置。(自己动手画一画就知道了)
class Solution { public: /** * 旋转数组 * @param n int整型 数组长度 * @param m int整型 右移距离 * @param a int整型vector 给定数组 * @return int整型vector */ vector<int> solve(int n, int m, vector<int>& a) { // write code here if(m%n == 0) return a; //若所要移动的位置是元素总数的整数倍,则相当于没移动。 else m %= n; //否则将右移距离除以元素总数取余。此举是为了减少计算移动后下标的计算量。 int temp1,temp2; //临时存储中间变量 int new_pos,idx = 0,i =0,cnt =0;//new_pos为当前元素移动后的下标,cnt指目前已移动了多少个元素,idx为移动的轮数,同时也代表每轮初始移动元素的下标,i指代当前元素移动前的下标。 for(idx;idx<=m;idx++) { if(cnt >= n) //所有元素均移动完毕 break; temp1=a[idx]; //暂存当前元素 i = idx; //初始化当前元素下标 while((i+m)%n!= idx) //只要当前元素移动后的下标不是最初的下标便继续循环。亦即移动这一轮的最后一个元素之前结束循环。 { new_pos = (i+m)%n; //新的下标=旧下标+移动位数 与元素总数n取余。 temp2 = a[new_pos]; //暂存当前新下标中的元素 a[new_pos] = temp1; //移动到新下标中 i = new_pos; //下一个处理的是之前存放在新下标中的老元素 temp1 = temp2; //temp1为即将进行移动的元素值 cnt++; //已经完成了一次移动 } a[idx] = temp1; //移动这一轮最后一个元素到新下标。由于每轮最后一次移动的元素的新下标为这一轮移动的第一个元素的老下标,形成了一个闭环,所以不再继续。 cnt++; //完成最后一次移动 } return a; //循环结束即代表已完成了所有的移动任务。返回。 } };
同种思想的另一种写法:
class Solution { public: /** * 旋转数组 * @param n int整型 数组长度 * @param m int整型 右移距离 * @param a int整型vector 给定数组 * @return int整型vector */ vector<int> solve(int n, int m, vector<int>& a) { // write code here int start = 0; int pos = start; int count = 0; int tmp1 = a[start]; int tmp2 = tmp1; m = m % n; while(true) { tmp1 = a[(pos + m) % n]; a[(pos + m) % n] = tmp2; tmp2= tmp1; pos = (pos + m) % n; count ++; if(count == n) break; if(pos == start) { start = start + 1; pos = start; tmp1 = a[start]; tmp2 = a[start]; } } return a; } };
解法2:
这个解法应该是这道题名字的由来,这也是网上最普遍的解法,即三次旋转解决问题。
该方法基于如下的事实:当我们将数组的元素向右移动 k 次后,尾部 k mod n 个元素会移动至数组头部,其余元素向后移动 k mod n个位置。
该方法为数组的翻转:我们可以先将所有元素翻转,这样尾部的 k mod n个元素就被移至数组头部,然后我们再翻转 [0, k mod n-1]区间的元素和 [k mod n, n-1]区间的元素即能得到最后的答案。
这里自己写了个reverse函数用于旋转数组。
class Solution { public: /** * 旋转数组 * @param n int整型 数组长度 * @param m int整型 右移距离 * @param a int整型vector 给定数组 * @return int整型vector */ void reverse(vector<int>& a,int start,int end){ while(start<end){ swap(a[start],a[end]); start++; end--; } } vector<int> solve(int n, int m, vector<int>& a) { m=m%n; reverse(a,0,n-1); reverse(a,0,m-1); reverse(a,m,n-1); return a; } };
这里充分运用了vector数组对象的方法begin()和end()以及STL中algorithm库的算法reverse,简化了步骤。
class Solution { public: /** * 旋转数组 * @param n int整型 数组长度 * @param m int整型 右移距离 * @param a int整型vector 给定数组 * @return int整型vector */ vector<int> solve(int n, int m, vector<int> &a) { // write code here if (!n) return a; if (!m) return a; m %= n; reverse(a.begin(), a.end()); reverse(a.begin(), a.begin() + m); reverse(a.begin() + m , a.end()); return a; } };
解法3:
此法抓住了题目的漏洞,既然题目不允许声明另外的数组,那我直接在你给的vector数组后面追加一模一样的元素。实质是使用辅助数组来直接移动。
该法同样活用了vector类的成员函数push_back(int),pop_back(),分别代表在数组尾部追加与删除元素。
class Solution { public: /** * 旋转数组 * @param n int整型 数组长度 * @param m int整型 右移距离 * @param a int整型vector 给定数组 * @return int整型vector */ vector<int> solve(int n, int m, vector<int>& a) { // write code here int M = m%n; for(int i = 0; i < n; i++) { a.push_back(a[i]); } for(int i = 0; i < n; i++) { a[i] = a[i+n-M]; } for(int i = 0;i<n;i++) { a.pop_back(); } return a; //return } };
参考来源:旋转数组__牛客网 (nowcoder.com)