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

基本实现 
如果不考虑时间复杂度,最简单的思路应该是从头扫描这个数组,每碰到一个偶数时,拿出这个数字,并把位于这个数字后面的所有的数字往前面挪动一位。挪完之后在数组的末尾有一个空位,这时把该偶数放入这个空位。由于没碰到一个偶数就需要移动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. UVA10140PrimeDistance题解--质数/技巧

    题目链接 https://www.luogu.org/problemnew/show/UVA10140 分析 \(L,R\)都很大,显然不能直接筛出\(L,R\)区间中的质数,这里需要一个结论 结论 ...

  2. caffe prototxt分析

    测试用prototxt name: "CIFAR10_quick"layer { name: "data" type: "MemoryData&quo ...

  3. Jupyter安装和环境配置

    配置: 1. 命令行启动 jupyter notebook 2. 也可以Anaconda直接启动 3. 设置token,如下图所示,命令行中输入 jupyter notebook list C:\Us ...

  4. Cacti-0.8.8b详细安装及配置步骤

    1.  Cacti环境安装 1.1         安装LAMP环境 安装LAMP环境,当然,如果你有兴趣可以采用编译,我线上Mysql是编译的,其余是yum安装的.在这次实验采用yum安装. 关闭i ...

  5. 01_日志采集框架Flume简介及其运行机制

    离线辅助系统概览: 1.概述: 在一个完整的大数据处理系统中,除了hdfs+mapreduce+hive组成分析系统的核心之外,还需要数据采集.结果数据导出. 任务调度等不可或缺的辅助系统,而这些辅助 ...

  6. D. Happy Tree Party CodeForces 593D【树链剖分,树边权转点权】

    Codeforces Round #329 (Div. 2) D. Happy Tree Party time limit per test 3 seconds memory limit per te ...

  7. CentOS7 内核优化 修改参数

    一:内核简介 内核是操作系统最基本的部分.它是为众多应用程序提供对计算机硬件的安全访问的一部分软件,这种访问是有限的,并且内核决定一个程序在什么时候对某部分硬件操作多长时间. 内核的分类可分为单内核和 ...

  8. 从Excel中读取数据并批量写入MySQL数据库(基于MySQLdb)

    一.Excel内容如下,现在需要将Excel中的数据全部写入的MySQL数据库中: 二.连接MySQL的第三方库使用的是“MySQLdb”,代码如下: # -*- coding:utf-8 -*-im ...

  9. BZOJ3073 [Pa2011]Journeys[最短路—线段树优化建边]

    新技能get✔. 线段树优化建边主要是针对一类连续区间和连续区间之间建边的题,建边非常的优秀.. 这题中,每次要求$[l1,r1]$每一点向$[l2,r2]$每一点建无向边,然后单元最短路. 暴力建边 ...

  10. loj2587 「APIO2018」铁人两项[圆方树+树形DP]

    主要卡在一个结论上..关于点双有一个常用结论,也经常作为在圆方树/简单路径上的良好性质,对于任意点双内互不相同的三点$s,c,t$,都存在简单路径$s\to c\to t$,证明不会.可以参见clz博 ...