问题描述:
You may have been using Java for a while. Do you think a simple Java array question
can be a challenge? Let’s use the following problem to test.
Problem: Rotate an array of n elements to the right by k steps. For example, with n
=
7
and k =
3
, the array [
1
,
2
,
3
,
4
,
5
,
6
,
7
] is rotated to [
5
,
6
,
7
,
1
,
2
,
3
,
4
].
How many different ways do you know to solve this problem?
您可能已经使用Java有一段时间了。你认为一个简单的Java数组问题会是一个挑战吗?让我们使用以下问题来进行测试。问题:通过k步,向右旋转n个元素的数组。例如,使用n = 7和k = 3,数组[1,2,3,4,5,6,7]被旋转到[5,6,7,1,2,3,4]。你知道有多少种不同的方法来解决这个问题?
我们可以写出三种难易不同,时间空间复杂度的算法来解决
方法一:
package LeetCode.demo01;
/**
* question01
*问题:通过k步,向右旋转n个元素的数组。
* 例如,使用n = 7和k = 3,数组[1,2,3,4,5,6,7]被旋转到[5,6,7,1,2,3,4]。
* 你知道有多少种不同的方法来解决这个问题?
*
* 1.简单数组方法 (时间空间复杂度都为O(n))
* @author 张子杰
*/
import java.util.Scanner;
public class Demo01 {
//主函数用来测试
public static void main(String[] args) {
// int[] nums={5,6,7,1,2,3,4};
// int k=3;
Scanner sc=new Scanner(System.in);
System.out.println("请输入数组的长度:");
int n=sc.nextInt();
System.out.println("请输入数组元素:");
int[] nums=new int[n];
for (int i = 0; i < nums.length; i++) {
nums[i]=sc.nextInt();
}
System.out.println("请输入要旋转步数:");
int k=sc.nextInt();
rotate(nums,k);
}
//解决方法,其实正确的解就是这个rotate方法去掉最后的打印,加上只是为了测试
public static void rotate(int[] nums, int k) {
if (k>nums.length) {
k=k%nums.length;
}
int[] result=new int[nums.length];
for (int i = 0; i < k ; i++) {
result[i]=nums[nums.length-k+i];
}
int j=0;
for (int i=k; i< nums.length; i++ ) {
result[i]=nums[j];
j++;
}
System.arraycopy(result,0,nums,0,nums.length);
for (int i = 0; i < nums.length ; i++) {
System.out.print(nums[i]+" ");
}
}
}
这个方法用到了一个System.arraycopy()函数
它的具体用法:
public class SystemArrayCopy {
public static void main(String[] args) {
int[] src = {1, 2, 3, 4};
int[] dest = new int[5];
System.arraycopy(src, 0, dest, 1, 4);
for (Object o : dest) {
System.out.println(o);
}
}
}
/*结果:
0 1 2 3 4
*/
/*
src = |1|2|3|4|
dest = |0|0|0|0|0|
执行System.arraycopy(src, 0, dest, 1, 4);时
第一步:从源数组(src)中,从下标0开始取,取4个,也就是src[0]-src[3],即1 2 3 4四个数
第二步:把取出的数,按顺序,存放到目标数组(dest)中,从下标1开始存,存4个,
也就是dest[1]-dest[4]
所以数组dest为:|0|1|2|3|4|
*/
方法二
package LeetCode.demo01;
/**
* question01
*问题:通过k步,向右旋转n个元素的数组。
* 例如,使用n = 7和k = 3,数组[1,2,3,4,5,6,7]被旋转到[5,6,7,1,2,3,4]。
* 你知道有多少种不同的方法来解决这个问题?
*
* 2. 空间复杂度为O(1)的方法
*类似冒泡排序 将最后一个元素冒泡排到最前面 重复n次,n为需要翻转的个数(次数)即可得到
* @author 张子杰
*/
public class Demo02 {
public static void main(String[] args) throws IllegalAccessException {
int[] nums={3,4,5,6,1,2};
int k=2;
rotate(nums,k);
}
public static void rotate(int[] arr,int order) throws IllegalAccessException {
if (order > arr.length || order < 0){
throw new IllegalAccessException("illegal argument!");
}
int temp;
for (int i = 0; i < order; i++) {
for (int j = arr.length-1; j >0 ; j--) {
temp=arr[j];
arr[j]=arr[j-1];
arr[j-1]=temp;
}
}
for (int i = 0; i < arr.length ; i++) {
System.out.print(arr[i]+" ");
}
}
}
方法三
package LeetCode.demo01;
/**
* question01
*问题:通过k步,向右旋转n个元素的数组。
* 例如,使用n = 7和k = 3,数组[1,2,3,4,5,6,7]被旋转到[5,6,7,1,2,3,4]。
* 你知道有多少种不同的方法来解决这个问题?
*
* 3.最优解 时间复杂度为O(1) 空间复杂度为O(n) 的算法
* 步骤:
*1.将数组分成两部分:1,2,3,4和5,6。
*2.旋转第一部分得到:4、3、2、1、5、6 。
*3.旋转第二部分:4、3、2、1、6、5 。
*4.旋转整个阵列:5、6、1、2、3、4
* @author 张子杰
*/
public class Demo03 {
public static void main(String[] args) {
int[] nums={1,2,3,4,5,6};
int k=2;
rotate(nums,k);
}
public static void rotate(int[] arr, int order) {
order = order % arr.length;
if (arr == null || order < 0) {
throw new IllegalArgumentException("Illegal argument!");
}
//length of first part
int a = arr.length - order;
reverse(arr, 0, a - 1);
reverse(arr, a, arr.length - 1);
reverse(arr, 0, arr.length - 1);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
}
public static void reverse(int[] arr, int left, int right) {
if (arr == null || arr.length == 1) {
return;
}
while (left < right) {
int temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
left++;
right--;
}
}
}