描述
输入一个长度为 n 整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前面部分,所有的偶数位于数组的后面部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
数据范围:0 \le n \le 50000≤n≤5000,数组中每个数的值 0 \le val \le 100000≤val≤10000
要求:时间复杂度 O(n)O(n),空间复杂度 O(n)O(n)
进阶:时间复杂度 O(n^2)O(n2),空间复杂度 O(1)O(1)
解题思路
1、先来一个时间复杂度O(n),控件复杂度O(n)的做法。
这里我借助了一个List列表来存放新的数据。之所以会选择List是因为它可以在列表指定位置插入数据,也可以在列表末尾插入数据。
很容易想到的思路就是:
1、新建一个List用来存放数据;
2、遍历原始数组,如果是偶数,则往list尾部插入数据;如果是奇数,则往list头方向从前往后数当前统计到的奇数个数的位置处插入该奇数。 所以需要借助一个整形变量来存储当前有多少了奇数数量。
public int[] reOrderArray (int[] array) {
//利用一个list来做辅助
nt length = array.length;
List<Integer> list = new ArrayList<Integer>();
nt oddNum = 0; //奇数数量
for (int i = 0; i < length; i++) {
if (array[i] % 2 != 0) {
list.add(oddNum, array[i]);//index位置前插入奇数
oddNum++;
} else {
list.add(array[i]); //后插入偶数
}
}
nt[] newarray = list.stream().mapToInt(Integer:: valueOf).toArray();
return newarray;
}
代码运行通过了,但是这种算法牛客网打出的分数很低。
2、再来一个时间复杂度
,控件复杂度O(n)的做法。
不借助外部空间,只在原始数组中进行遍历和执行一些操作也能满足要求。
算法思路为:
1、从下标0开始遍历数组元素,并使用一个整形变量evenNum来统计已有的偶数数量;
2、如果当前元素为偶数,则直接evenNum++,然后进行下一次循环;---保证偶数之间的顺序
3、如果当前元素为奇数,则对下标为i-evenNum ~ i区间的子数组做下处理,把array[i]旋转到子数组第一个位置i-evenNum, 其他元素全部往后移一个位置。 ---保证奇数在偶数之前,并保证奇数之间的顺序。
4、这样可以保证所有奇数在偶数前面,并且其内部的顺序保持不变。
文字不好描述算法的演进过程,建议还是动手动笔用一个例子画一个,就能理解整个算法过程了。
public int[] reOrderArray (int[] array) {
//不借助外部数组
int length = array.length;
int evenNum = 0; //偶数数量
for (int i =0 ; i < length; i++) {
if (array[i] % 2 != 0) {
roateLastOfArray(array, i - evenNum, i);
} else {
evenNum++;
}
}
return array;
}
public void roateLastOfArray(int [] array, int start, int end) {
int last = array[end];
for (int i = end; i > start; i--) {
array[i] = array[i - 1];
}
array[start] = last;
}
运行成功,分数较之前有明显提升
也可以参考网上其他的人的做法
CodeSolution/剑指Offer13-调整数组顺序使奇数位于偶数前面.md at main · Damaer/CodeSolution · GitHub