一个数组a中存有n(>0)个整数,将每个整数循环向右移m(≥0)个位置,即将a中的数据由(a 0 a 1 … a n−1 )变换为(a n−m … a n−1 a 0 a 1 … a n−m−1 )(最后m个数循环移至最前面的m个位置)。
时间: 2023-05-31 16:19:23 浏览: 425
### 回答1:
可以使用以下方法实现循环右移:
1. 将数组a中的元素分为两部分:a[]到a[n-m-1]和a[n-m]到a[n-1]。
2. 将第一部分的元素往右移动m个位置,即将a[]到a[n-m-1]变为a[m]到a[n-1]和a[]到a[m-1]。
3. 将第二部分的元素往右移动m个位置,即将a[n-m]到a[n-1]变为a[]到a[m-1]和a[n-m]到a[n-m-1]。
4. 将两部分的元素合并,即将a[m]到a[n-1]和a[]到a[m-1]合并为一个数组。
示例代码:
void rotate(int a[], int n, int m) {
m = m % n; // 处理m大于n的情况
int temp[m];
for (int i = n - m; i < n; i++) {
temp[i - n + m] = a[i];
}
for (int i = n - m - 1; i >= ; i--) {
a[i + m] = a[i];
}
for (int i = ; i < m; i++) {
a[i] = temp[i];
}
}
调用示例:
int a[] = {1, 2, 3, 4, 5};
int n = 5, m = 2;
rotate(a, n, m);
// 输出:3 4 5 1 2
### 回答2:
题目描述
我们有一个长度为 $n$ 的数组 $a$,将其中的元素循环向右移动 $m$ 个位置,即将 $a$ 中的数据由 $(a_0,a_1,...,a_{n-1})$ 变换为 $(a_{n-m},...,a_{n-1},a_0,a_1,...,a_{n-m-1})$。其中 $n$,$m$ 和每个元素的取值范围都不超过 $10^4$。
思路分析
要把数组元素循环向右移动 $m$ 个位置,最简单的思路是将后 $m$ 个元素移到前面来,然后将前 $n-m$ 个元素移到后面来。但是显然这种做法的时间复杂度是 $O(nm)$,不可行。我们需要使用更高效的算法。
观察题目中要求的变换,我们可以发现一个性质:整个数组中的元素实际上被分成了两段,一段是后 $m$ 个元素,另一段是前 $n-m$ 个元素。这两段元素的顺序没有改变,只是在整个数组中的位置发生了变化。
举个例子,假设原数组为 [1,2,3,4,5,6],要将其右移 2 个位置,那么整个数组中的元素可以分成两段:
- 后 2 个元素:[5,6]
- 前 4 个元素:[1,2,3,4]
将这两段元素分别逆序排列,得到:
- 后 2 个元素:[6,5]
- 前 4 个元素:[4,3,2,1]
然后将这两段元素拼接起来,得到最终结果:[6,5,4,3,2,1]。
通过这种方法,我们只需要进行两次反转操作,就可以得到想要的结果。显然,这种做法的时间复杂度是 $O(n)$,非常高效。
具体实现
我们可以先将整个数组反转一下,然后将数组的前 $m$ 个元素反转,将数组的后 $n-m$ 个元素反转,最后再将整个数组反转回来即可。
我们可以先写一个函数来实现数组反转操作:
void reverse(vector<int>& nums, int left, int right) {
while (left < right) {
swap(nums[left], nums[right]);
left++;
right--;
}
}
然后再写一个函数来实现将数组中的元素循环向右移动 $m$ 个位置的操作:
void rotate(vector<int>& nums, int m) {
int n = nums.size();
m = m % n;
if (m == 0) return;
reverse(nums, 0, n - 1);
reverse(nums, 0, m - 1);
reverse(nums, m, n - 1);
}
这个函数中,首先将 $m$ 模 $n$,以确保 $m$ 不会大于 $n$。然后,调用 reverse 函数进行反转操作即可,非常简单。
完整代码
最后,附上完整的代码实现:
#include <iostream>
#include <vector>
using namespace std;
void reverse(vector<int>& nums, int left, int right) {
while (left < right) {
swap(nums[left], nums[right]);
left++;
right--;
}
}
void rotate(vector<int>& nums, int m) {
int n = nums.size();
m = m % n;
if (m == 0) return;
reverse(nums, 0, n - 1);
reverse(nums, 0, m - 1);
reverse(nums, m, n - 1);
}
int main() {
vector<int> nums = {1, 2, 3, 4, 5, 6};
int m = 2;
rotate(nums, m);
for (int i = 0; i < nums.size(); i++) {
cout << nums[i] << " ";
}
cout << endl;
return 0;
}
### 回答3:
题目描述:
有一个长度为n的数组a,请将每个元素向右循环移动m个位置,并输出移动后的结果。
解题思路:
一种简单的解法是使用一个长度为m的临时数组来暂存需要移动的数,然后将原数组的后n-m个元素向右移动m个位置,最后再将临时数组中的m个元素赋值到原数组的前m个位置即可。这种解法的时间复杂度为O(n),空间复杂度为O(m)。
另一种更简便的解法是使用翻转。首先将整个数组翻转,然后再将前m个元素和后n-m个元素分别翻转,最后再将整个数组翻转回来。这种解法的时间复杂度为O(n),空间复杂度为O(1)。
实现代码(使用翻转):
```
void rotate(int a[], int n, int m) {
// 将整个数组翻转
reverse(a, a + n);
// 将前m个元素翻转
reverse(a, a + m);
// 将后n-m个元素翻转
reverse(a + m, a + n);
}
```
测试样例:
假设原数组a为{1,2,3,4,5,6,7},需要将每个元素向右移动3个位置,则移动后的结果为{5,6,7,1,2,3,4}。
阅读全文