题目描述: 
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。

基本实现 
如果不考虑时间复杂度,最简单的思路应该是从头扫描这个数组,每碰到一个偶数时,拿出这个数字,并把位于这个数字后面的所有的数字往前面挪动一位。挪完之后在数组的末尾有一个空位,这时把该偶数放入这个空位。由于没碰到一个偶数就需要移动O(n)个数字,因此总的时间复杂度是O(n2).但是,这种方法不能让面试官满意。不过如果我们在听到题目之后马上能够说出这个解法,面试官至少会觉得我们的思维非常灵敏。

只完成基本功能的解法,仅适用于初级程序员 
这个题目要求把奇数放在数组的前半部分,偶数放在数组的后半部分,因此所有的奇数应该位于偶数的前面,也就是说我们在扫描这个数组的时候,如果发现有偶数在奇数的前面,我们可以交换他们的数序,交换之后就符合要求了。 
因此我们可以维护两个指针,第一个指针初始化时指向数组的第一个数字,它只向后移动;第二个指针初始化时指向数组的最后一个数字,它指向前移动。在两个指针相遇之前,第一个指针总是位于第二个指针的前面。如果第一个指针的数字是偶数,并且第二个指针指向的数字是奇数,我们就交换两个数字。 

考虑可扩展性的解法,秒杀Offer 
如果是面试应届毕业生或者工作时间不长的程序员,面试官会满意前面的代码,但如果应聘者申请的是资深的开发职位,那面试官可能会接着问几个问题。

面试官:如果把题目改成数组中的数按照大小分为两部分,所有的负数在所有的非负数的前面,该怎么做?

如果再把题目改改,变成 把数组中的数分成两部分,能被3整除的数都在不能被3整除的数的前面,怎么办?

这就是面试官在考察我们对可扩展性的理解,即希望我们能够给出一个模式,在这个模式下能够很方面第把已有的解决方案扩展到同类型的问题上去。

代码如下:

public class Offer21 {
public static void main(String[] args) {
int[] arr = { 1, 2, 3, 4, 5, 6, 7 };
change(arr, OPER_TYPE.ODDEVEN);
for (int i : arr) {
System.out.print(" " + i);
}
} public static void change(int[] arr, OPER_TYPE type) {
if (arr.length == 0 || arr == null) {
return;
}
int left = 0;
int right = arr.length - 1;
while (left < right) {
// func(type, arr[left])
while (left < right && (arr[left] & 1) == 1) {
left++;
}
// !func(type, arr[right])
while (right > left && (arr[right] & 1) == 0) {
right--;
}
int temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
}
}
}

在上面的代码中,虽然功能已经完成了,但是按照面试官所说的,一会改成负数正数交换,一会3的整除数换,那我们写代码的还不是疯了,天天改方法核心源码,所以我们想,核心源码不动(因为这道题除了判断条件改变外,其他都可以不改动),所以我进行了改进:

public class Offer21 {
public static void main(String[] args) {
int[] arr = { 1, 2, 3, 4, 5, 6, 7 };
change(arr, OPER_TYPE.ODDEVEN);
for (int i : arr) {
System.out.print(" " + i);
}
System.out.println();
int[] arr1 = { 3, 5, 6, 9, 7, 12 };
change(arr1, OPER_TYPE.THREE);
for (int i : arr1) {
System.out.print(" " + i);
}
System.out.println();
int[] arr2 = { -3, 5, -6, 9, -7, 12 };
change(arr2, OPER_TYPE.PLUSORMINUS);
for (int i : arr2) {
System.out.print(" " + i);
}
} public static void change(int[] arr, OPER_TYPE type) {
if (arr.length == 0 || arr == null) {
return;
}
int left = 0;
int right = arr.length - 1;
while (left < right) {
//
while (left < right && func(type, arr[left])) {
left++;
}
//
while (right > left && !func(type, arr[right])) {
right--;
}
int temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
}
} private static boolean func(OPER_TYPE type, int num) {
if (type == null) {
return true;
}
switch (type) {
case ODDEVEN:
return funcODDEVEN(num);
case PLUSORMINUS:
return PLUSORMINUS(num);
case THREE:
return THREE(num);
default:
return true;
}
} private static boolean THREE(int num) {
return num % 3 == 0 ? true : false;
} private static boolean PLUSORMINUS(int num) {
return num < 0 ? true : false;
} private static boolean funcODDEVEN(int num) {
return (num & 1) == 1 ? true : false;
}
} // 定义枚举的意义:让功能选择更加严格化
enum OPER_TYPE {
ODDEVEN("奇偶"), PLUSORMINUS("正负"), THREE("3整除"); private String type; OPER_TYPE(String type) {
this.type = type;
} public String getType() {
return type;
} }

在上面的代码中,func方法已经很好地解决了面试官所关心的问题,我们只需要传一个功能选项(枚举),就可以让方法知道当前我们的意愿,并调用那些封装好的方法,这样就做到了程序的可扩展性!

剑指offer21----数组中奇数偶数的更多相关文章

  1. leetcode 136. Single Number 、 137. Single Number II 、 260. Single Number III(剑指offer40 数组中只出现一次的数字)

    136. Single Number 除了一个数字,其他数字都出现了两遍. 用亦或解决,亦或的特点:1.相同的数结果为0,不同的数结果为1 2.与自己亦或为0,与0亦或为原来的数 class Solu ...

  2. 剑指offer之 调整奇数偶数数组位置

    package Problem14; /* * 问题描述: * 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位与数组的前半部分,所有偶数位与数组的 * 后半部分 */ publ ...

  3. 剑指Offer——数组中只出现一次的数字

    题目描述: 一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字. 分析: 数组中一共有偶数个数.两个数字只出现过一次. 相同数异或在一起等于0,那么将所有数异或 ...

  4. 剑指Offer——数组中的逆序对(归并排序的应用)

    蛮力: 遍历数组,对每个元素都往前遍历所有元素,如果有发现比它小的元素,就count++. 最后返回count取模. 结果没问题,但超时哈哈哈,只能过50%.   归并法: 看讨论,知道了这道题的经典 ...

  5. 剑指 Offer —— 数组中重复的数字

    数组中的重复数字 题目描述 牛课网链接 长度为 n 的数组里,所有数字都在 0 到 n-1 的范围内. 数组中某些数字是重复的,但不知道有几个数字是重复的.也不知道每个数字重复几次.请找出数组中任意一 ...

  6. 剑指offer 数组中重复的数

    在一个长度为n的数组里的所有数字都在0到n-1的范围内. 数组中某些数字是重复的,但不知道有几个数字是重复的.也不知道每个数字重复几次.请找出数组中任意一个重复的数字. 例如,如果输入长度为7的数组{ ...

  7. 剑指offer-56数组中数字出现的次数

    题目 一个整型数组 nums 里除两个数字之外,其他数字都出现了两次.请写程序找出这两个只出现一次的数字.要求时间复杂度是O(n),空间复杂度是O(1). 输入:nums = [4,1,4,6] 输出 ...

  8. 剑指Offer 数组中只出现一次的数字

    题目描述 一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字.   思路: 因为有2个数字只出现了一次,而其他的数字都是2次,可以通过异或运算,得到最后这2个只 ...

  9. [剑指OFFER] 数组中的逆序对

    题目描述 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数.     分析:利用归并排序的思想,分成2部分,每一部分按照从大到 ...

随机推荐

  1. 【图像处理 】 一、OSTU分割法

    图像中像素的灰度值小于阈值T的像素个数记作N0,像素灰度大于阈值T的像素个数记作N1,则有: 图像大小:M*N T为二值化的阈值: N0为灰度小于T的像素的个数,N0的平均灰度为μ0 N1 为灰度大于 ...

  2. 在Android8.0以上收不到广播问题(AppWidget)

    对Intent指定组件 //安卓8.0必须添加 intent.setComponent(new ComponentName(context,MyAppWidgetProvider.class)); 问 ...

  3. JDK,JRE,JVM 关系和概念

    JDK : Java Development ToolKit(Java开发工具包).JDK是整个JAVA的核心,包括了Java运行环境(Java Runtime Envirnment),一堆Java工 ...

  4. UART串口简介

    通用异步收发传输器(Universal Asynchronous Receiver Transmitter) 原理 发送数据时,CPU将并行数据写入UART,UART按照一定的格式在一根电线上串行发出 ...

  5. list列表的使用

    Python最常用的数据类型之一,通过列表可以对数据实现最方便的存储.修改等操作 list1 = [1,2,3,4,5,6,7,8,9] #创建列表 z = list([1,2,3,4,5,6,7,8 ...

  6. linux和unix下crontab的使用

    在LINUX中,周期执行的任务一般由cron这个守护进程来处理 [ps -ef | grep cron].cron读取一个或多个配置文件,这些配置文件中包含了命令行及其调用时间.cron的配置文件称为 ...

  7. 解决安卓app在真机上的无法登录问题

    和小伙伴用安卓做的app在模拟器上可以正常使用,但是变成apk发到手机上下载使用时,出现无法的登录问题,而且登录提示的错误出现一秒就消失了,无法看清. 于是找了一下老师帮忙,老师是通过在电脑主机上插入 ...

  8. HTML table 边框双线变单线

    table{border-collapse:collapse;border-spacing:0;border-left:1px solid #888;border-top:1px solid #888 ...

  9. WHU个人赛第二场C——前缀和&&后缀和

    题目 链接 题意:给定 $n$ 个整数,去掉其中一个数使得剩下数字的gcd最大,求最大的gcd.($3 \leq n \leq 100000$) 分析 枚举每一个位置,显然每次枚举都计算所有数的gcd ...

  10. 音频转换 wav to wav、mp3或者其它

    1.首先介绍一种NAudio 的方式 需要导入 NAudio.dll 下面请看核心代码 using (WaveFileReader reader = new WaveFileReader(in_pat ...