目录
题目:
输入一个长度为 n 整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前面部分,所有的偶数位于数组的后面部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
数据范围:0<n ≤5000,数组中每个数的值0≤val ≤10000
要求:时间复杂度O(n),空间复杂度O(n)
进阶:时间复杂度O(n^2),空间复杂度O(1)
解答方案(一):双指针方法
public class Test {
public static int[] test(int[] array) {
//数组长度len
int len = array.length;
//辅助数组b
int b[] = new int[len];
int i = 0; //指针1,从前往后 寻找奇数
int i1 = i;
int j = array.length - 1; //指针2,从后往前 寻找偶数
int j1 = j;
while (i1 < len && j1 >= 0) { //终止条件
//判断奇数
if (array[i1] % 2 == 1) {
b[i1++] = array[i];
}
i++; //右移指针i
//判断偶数
if (array[j1] % 2 == 0) {
b[j1--] = array[j];
}
j--; //左移指针j
}
return b;
}
public static void main(String[] args) {
int[] b = {1,2,3,4,5};
int[] c = test(b);
System.out.println(Arrays.toString(c));
}
}
//输出结果
[1, 3, 5, 2, 4]
时间复杂度O(n),需要遍历原数组
空间复杂度O(n) ,n为辅助数组空间
双指针图解
解答方案(二):插入排序法
在原数组的基础上修改,找到一个奇数就把这个奇数往前挪,所以需要记录当前有多少个奇数,如果当前有k个奇数,那接下来找到的奇数原本在 array[ j ] 则需要挪到array[ k ]上,而array[ k ]——array[ j-1 ]需要后移一位,挪到array[ k+1 ]——array[ j ]处。
变量 i 记录奇数,表示奇数的下一个位置,最开始 i=0 表示没有一个奇数。j 表示数组的下标,对数组进行遍历。
a. 若遇到偶数则 j++
b. 若遇到奇数,将 j 位置的奇数插入到 i 的位置,然后将 i 后移一位,会涉及 [ i , j-1] 整体移动,直到整个数组遍历结束。
public class Test {
public static int[] a(int[] array) {
int i = 0; //i的作用,遇到奇数跳过,找到偶数停下
for (int j = 0; j < array.length; j++) {
//处理偶数,遇到偶数j++
if (array[j] % 2 ==0 ) {
continue;
}
//j的作用,遇到偶数跳过,指向找到奇数
int tmp = array[j];//临时变量保存此时的奇数
//将[i,j-1]中的元素,整体向后移动1格,这里移动的[i,j-1]均为偶数
int k = j-1;
while (k >= i) {
array[k+1] = array[k];
k--;
}
//将刚才j下标保存的奇数,放入移动操作后的空缺处
array[i++] = tmp;
}
return array;
}
public static void main(String[] args) {
int[] b = {1,2,3,4,5};
int[] d = a(b);
System.out.println(Arrays.toString(d));
}
}
//输出结果
[1, 3, 5, 2, 4]
时间复杂度O(n^2),最差情况,偶数都在奇数之前
空间复杂度O(1),插入排序只需要一个额外的tmp变量
插入排序图解
总结
1. 利用双指针双向遍历,可解决数组越界等问题。
2. 需要熟悉插入排序的方法,才能更好实现在数组本身的移动。