剑指offer21----数组中奇数偶数
题目描述:
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。
基本实现
如果不考虑时间复杂度,最简单的思路应该是从头扫描这个数组,每碰到一个偶数时,拿出这个数字,并把位于这个数字后面的所有的数字往前面挪动一位。挪完之后在数组的末尾有一个空位,这时把该偶数放入这个空位。由于没碰到一个偶数就需要移动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----数组中奇数偶数的更多相关文章
- leetcode 136. Single Number 、 137. Single Number II 、 260. Single Number III(剑指offer40 数组中只出现一次的数字)
136. Single Number 除了一个数字,其他数字都出现了两遍. 用亦或解决,亦或的特点:1.相同的数结果为0,不同的数结果为1 2.与自己亦或为0,与0亦或为原来的数 class Solu ...
- 剑指offer之 调整奇数偶数数组位置
package Problem14; /* * 问题描述: * 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位与数组的前半部分,所有偶数位与数组的 * 后半部分 */ publ ...
- 剑指Offer——数组中只出现一次的数字
题目描述: 一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字. 分析: 数组中一共有偶数个数.两个数字只出现过一次. 相同数异或在一起等于0,那么将所有数异或 ...
- 剑指Offer——数组中的逆序对(归并排序的应用)
蛮力: 遍历数组,对每个元素都往前遍历所有元素,如果有发现比它小的元素,就count++. 最后返回count取模. 结果没问题,但超时哈哈哈,只能过50%. 归并法: 看讨论,知道了这道题的经典 ...
- 剑指 Offer —— 数组中重复的数字
数组中的重复数字 题目描述 牛课网链接 长度为 n 的数组里,所有数字都在 0 到 n-1 的范围内. 数组中某些数字是重复的,但不知道有几个数字是重复的.也不知道每个数字重复几次.请找出数组中任意一 ...
- 剑指offer 数组中重复的数
在一个长度为n的数组里的所有数字都在0到n-1的范围内. 数组中某些数字是重复的,但不知道有几个数字是重复的.也不知道每个数字重复几次.请找出数组中任意一个重复的数字. 例如,如果输入长度为7的数组{ ...
- 剑指offer-56数组中数字出现的次数
题目 一个整型数组 nums 里除两个数字之外,其他数字都出现了两次.请写程序找出这两个只出现一次的数字.要求时间复杂度是O(n),空间复杂度是O(1). 输入:nums = [4,1,4,6] 输出 ...
- 剑指Offer 数组中只出现一次的数字
题目描述 一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字. 思路: 因为有2个数字只出现了一次,而其他的数字都是2次,可以通过异或运算,得到最后这2个只 ...
- [剑指OFFER] 数组中的逆序对
题目描述 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数. 分析:利用归并排序的思想,分成2部分,每一部分按照从大到 ...
随机推荐
- Vue-img-preload
预加载页面上的图片资源,提高用户体验 效果预览 使用方法 下载vue-img-preload插件 npm install vue-img-preload 配置参数 eachLoaded(functio ...
- jQuery 手写菜单(ing)
菜单支持多级 直接上代码 <!DOCTYPE html> <html lang="en"> <head> <meta charset=&q ...
- vue组件常用传值
一.使用Props传递数据 在父组件中使用儿子组件 <template> <div> 父组件:{{mny}} <Son1 :mny="mny"&g ...
- spring依赖注入时,什么时候会创建代理类
spring 依赖注入时,什么时候会创建代理类 有的会创建代理类来替代目标类的实现.比如有事务注解啊 有的直接使用目标类.啥拦截配置都没有.
- Redis分布式缓存安装和使用
独立缓存服务器: LinuxCentOS Redis版本: 3.0 下面我们针对于Redis安装做下详细的记录: 编译和安装所需的包: #yum install gcc tcl创建安装目录:贵州中医肝 ...
- Django:中间件与csrf
一.中间件 什么是中间件 中间件有什么用 自定义中间件 中间件应用场景 二.csrf csrf token跨站请求伪造 一.中间件 什么是中间件 中间件顾名思义,是介于request与response ...
- java——jdbc调用存储过程
1,加载驱动: 2,获取连接 3,设置参数 4,执行: 5,释放连接 普通jdbc的执行过程: conn.prepareCall() 上面是一个调用存储过程的示例.
- springboot同时支持访问html5和jsp时,导致后台ResponseBody返回中文乱码
背景:原系统是由springboot jsp,所有访问都是jsp 现在需要做HTML5定位,要同时支持访问HTML5和JSP 在application.yml的spring标签下配置 mvc: #vi ...
- Java笔记(第六篇-网络通信)
TCP/IP模式是一种层次结构,共分为四层,分别为应用层.传输层.互联网层和主机到网络层. 在TCP/IP协议栈中,有两个高级协议是网络应用程序编写者应该了解的,即“传输控制协议”(TCP)与“用户数 ...
- Mapreduce案例之Pi值估算
题目: 这个程序的原理是这样的.假如有一个边长为1的正方形.以正方形的一个端点为圆心,以1为半径,画一个圆弧,于是在正方形内就有了一个直角扇形.在正方形里随机生成若干的点,则有些点是在扇形内,有些点是 ...