问题描述:
将n(n>1)个整数存放在一维数组R中,设计一个在时间和空间两方面都尽可能高效的算法。 将R中保存的序列循环左移p(0<p<n)个位置,即将R中的数据(x0,x1,x2,…x(n-1))变换为(xp,x(p+1),…,x(n-1),x0,x1,…,x(p-1))
示例:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
左移4位
[5, 6, 7, 8, 9, 10, 1, 2, 3, 4]
中间数组辅助法
解题思路:定义一个中间数组temp[ ] 来辅助 R[ ]数组 的元素进行移动。
- 看下面代码的
reverse
方法,共有3个for
循环。这3个for
循环,是该算法实现元素循环左移的核心代码.
假设数组R
= [1,2,3,4,5,6,7,8,9,10] ,向左移动4位 (p = 4
)
- 第一个
for
循环:将数组R中,前p个元素 暂存到 temp数组中。 - 第二个
for
循环:将数组R中,后n-p个元素整体左移p个位置。(其实左移用在这里不太恰当,应该说:将后n-p个元素的值 赋给 前n-p个元素) - 第三个
for
循环:将第一个 for 循环中,暂存在 temp 数组中的元素,依序赋值给 R数组中的后p个元素
public class Solution_3 {
public static void reverse(int[] R, int p) {
//中间数组
int[] temp = new int[R.length];
//将R数组中,前p个元素 暂存到 temp数组中
for (int i = 0; i < p; i++) {
temp[i] = R[i];
}
//将R数组中,后n-p个元素整体左移p个位置
for (int i = p; i < R.length; i++) {
R[i-p] = R[i];
}
//将暂存在 temp 数组中的元素,依序赋值给 R数组中的后p个元素
int start = 0;
for (int i = R.length-p; i < R.length; i++) {
R[i] = temp[start++];
}
}
public static void main(String[] args) {
int[] R = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int p = new Scanner(System.in).nextInt();
reverse(R, p);
//将数组以字符串格式打印输出
System.out.println(Arrays.toString(R));
}
}
时空复杂度:该算法只有单层循环,时间复杂度为O(n),因为外部内存中开了一个长度为n的中间数组,空间复杂度也为O(n)。
代码优化:前面reverse
方法中,第一第二个代码我们可以进行合并。
解析:将元素暂存到temp数组 和 将R数组元素左移的步骤合并到一个for循环中。但需要注意的是,前面第一个for循环是直接将p个元素暂存到temp数组中。而合并后,是将n-p个元素暂存到temp数组中。因为R数组中有n-p个元素需要左移。
for (int i = 0; i < R.length-p; i++) { // T(n) = 3n = O(n)
//将R数组中,前n-p个元素 暂存到 temp数组中
temp[i] = R[i];
//将R数组的后n-p个元素 赋值 给前面的n-p个元素
R[i] = R[i + p];
}
时空复杂度:这一步并没有降低算法的时间复杂度,还是O(n)。仅仅只是代码量减少了
数组元素逆置法
解题思路:将R数组分割成a,b两个部分,然后分别将a,b两个部分的元素逆置,最后再将R数组整体逆置。所以需要三次调用元素逆置算法 。
public class Solution_2 {
private static void reverse(int[] R, int left, int right) {
//数组元素互置算法(其实就是两个数的互换)
for(int i = 0; i <= (right - left)/2; i++){
int temp = R[left + i];
R[left + i] = R[right - i];
R[right - i] = temp;
}
}
private static void move(int[] R, int n, int p) {
//将数组中第一部分的元素逆置
reverse(R,0,p - 1);
//将数组中第二部分的元素逆置
reverse(R, p,n - 1);
//将整个数组的元素逆置
reverse(R,0,n - 1);
}
public static void main(String[] args) {
int[] R = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int p = new Scanner(System.in).nextInt();
move(R, R.length, p);
//以字符串格式,将数组打印输出
System.out.println(Arrays.toString(R));
}
}
时空复杂度:该算法中用的都是一重循环,时间复杂度为O(n),因为基本没有用到外部内存,空间复杂度为O(1)。