题目描述:
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分。
分析:
最简单的思路:从头到尾扫描数组,每次遇到一个偶数,则取出该数,将其后的所有数字向前移动1位,则可以将该数放置在数组末尾。每次碰到偶数需要移动
O(n)
,则总的时间复杂度为
O(n2)
参考快速排序的思路:维护两个指针,第一个指针start初始指向第一个元素,向后移动;第二个指针end初始指向最后一个元素,向前移动。在两个指针相遇前,start总是在end前面。移动过程中如果遇到start指向的元素为偶数,并且end指向的元素为奇数,则交换两个元素。
代码:
/**
* 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,
* 使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分
* key:
* 使用前后两个指针,从头部和尾部相向移动
* 如果第一个指针为偶数,第二个指针为基数,则交换,
* 直到第二个指针移动到第一个指针前面,结束循环;
* @param array
*/
public void reorder(int[] array) {
if(array == null)
return;
int start = 0;
int end = array.length - 1;
while(start < end) {
while(start < end && isEven(array[start]))
start++;
while(start < end && !isEven(array[end]))
end--;
// 交换
if(start < end) {
swap(array, start, end);
}
}
}
// 判断是否是偶数
public boolean isEven(int x) {
return (x & 1) == 0 ? true : false;
}
// 交换数组元素
public void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
推荐思路扩展:
原题中给定的要求是将所有奇数调整位于偶数前面,如果更换为其他的调整要求,则上面的解法也得更改代码。如:所有负数在非负数前面、所有被3整除的在不被3整除的前面、类似的其他条件等。为了使程序具有更好的可扩展性,定义一个调整要求条件的接口,每个调整的条件需要实现该接口,以参数的方式传递给重排序函数,即可实现动态绑定。
代码:
public class ReorderArray {
public static void main(String[] args) {
int[] array = {1, 8, -9, 21, -34, -2, 4, -3, 5};
ReorderArray reorderArray = new ReorderArray();
reorderArray.reorder2(array, new NegetiveCondition());
for(int i : array)
System.out.print(i + ",");
}
/**
* 输入一个整数数组,实现一个函数来调整该数组中数字的顺序
*
* 1、使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分;
* 2、所有负数在非负数前面
* 3、所有被3整除的在不被3整除的前面
* 4、类似的其他条件...
*
* key:
* 传递一个接口作为参数,判断调整的条件
* @param array
*/
public void reorder2(int[] array, ICondition condition) {
if(array == null)
return;
int start = 0;
int end = array.length - 1;
while(start < end) {
while(start < end && condition.isConditionMeet(array[start]))
start++;
while(start < end && !condition.isConditionMeet(array[end]))
end--;
if(start < end) {
swap(array, start, end);
}
}
}
// 交换数组元素
public void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
/** 以下接口和类在同一个.java文件中,仅同一个package可见 **/
/** 条件判断接口 **/
interface ICondition {
public boolean isConditionMeet(int n);
}
// 判断是否为偶数
class EvenCondition implements ICondition {
@Override
public boolean isConditionMeet(int n) {
if((n & 1) == 0)
return true;
else
return false;
}
}
// 判断是否为负数
class NegetiveCondition implements ICondition {
@Override
public boolean isConditionMeet(int n) {
if(n <= 0)
return true;
else
return false;
}
}
题目扩展:
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
分析:
此题需要保持相对位置不变,前面所说的类似快速排序的方式是不稳定的排序方法,因此并不能保证相对位置不变。
可以参考插入排序、归并排序和参考冒泡排序,相邻的两个数,如果左边是偶数,右边是奇数,则发生交换。
冒泡排序参考的牛客AC代码:
public class Solution {
public void reOrderArray(int [] array) {
if(array == null)
return;
for(int i = 1; i < array.length; i++) {
for(int j = i; j > 0; j --) {
if(isEven(array[j - 1]) && !isEven(array[j])) {
int tmp = array[j];
array[j] = array[j - 1];
array[j - 1] = tmp;
}
}
}
}
public boolean isEven(int x) {
return (x & 1) == 0 ? true : false;
}
}
参考
1. 何海涛,剑指offer名企面试官精讲典型编程题(纪念版),电子工业出版社