剑指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方法已经很好地解决了面试官所关心的问题,我们只需要传一个功能选项(枚举),就可以让方法知道当前我们的意愿,并调用那些封装好的方法,这样就做到了程序的可扩展性!

原文地址:https://www.cnblogs.com/Booker808-java/p/9261282.html

时间: 2024-10-09 12:11:47

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

剑指offer 数组中的逆序对

题目描述 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数P.并将P对1000000007取模的结果输出. 即输出P%1000000007 输入描述: 题目保证输入的数组中没有的相同的数字 数据范围: 对于%50的数据,size<=10^4 对于%75的数据,size<=10^5 对于%100的数据,size<=2*10^5 示例1 输入 1,2,3,4,5,6,7,0 输出 7 思路:归并排序的思路.具体参考剑指

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

数组中的重复数字 题目描述 牛课网链接 长度为 n 的数组里,所有数字都在 0 到 n-1 的范围内. 数组中某些数字是重复的,但不知道有几个数字是重复的.也不知道每个数字重复几次.请找出数组中任意一个重复的数字. 例如,如果输入长度为 7 的数组{2,3,1,0,2,5,3},那么对应的输出是重复的数字 2 或者 3.(牛课网这里弄成「那么对应的输出是第一个重复的数字 2」了) A 简单实现思路 借助外部数组 b,原数组中的数字记为外部数组的下标,外部数组的值来存储这个数字出现的次数.原数组中

剑指offer_数组中的逆序对

题目描述 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数P. 并将P对1000000007取模的结果输出. 即输出P%1000000007 本题采用归并排序,归并排序算法我在前一篇博客里写到过,在那个基础上进行修改即可!(强烈建议先理解归并排序的具体算法后,再来做此题) public class Solution36 { private int count = 0; //记录次数 private int[] copy ;

剑指offer——数组中的逆序对

数组中的逆序对 **(不会)数据结构--小和问题 逆序对问题 原文地址:https://www.cnblogs.com/SkyeAngel/p/8978980.html

python剑指offer数组中出现次数超过一半的数字

题目描述 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2.如果不存在则输出0. 思路: 两种思路.第一种思路,出现次数超过一半的数字,不管如何,必然这个数字位于数组中间的位置,因此可以采用类似于快排的划分的方法,找到位于数组中间的位置的数字,然后在顺序检索是否这个数字出现次数超过一半.第二种思路根据数组的特点,出现次数超过一半的数,他出现的次数比其他数字出

剑指offer——数组中出现次数超过一半的数字(c++)

题目描述数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2.如果不存在则输出0. 思路一遍历数组是保存两个值:一个是数字中的一个数字,另一个是次数.当遍历到下一个数字的时候,如果下一个数字和之前保存的数字相等,则次数加1:如果不同,则次数减1:如果次数为零,那么我们需要保存下一个数字,并把次数设置为1.由于我们要找的数字出现的次数比其他所有数字出现的次数之和还

剑指Offer40:数组中只出现一次的数字(Java)

参考hezhiyao的博客 https://www.cnblogs.com/hezhiyao/p/7539024.html 参考qmss的博客 https://www.jianshu.com/p/c308e4a1e19f 参考Raise的博客 https://blog.csdn.net/linraise/article/details/9425319 思路分析: 利用两个相同的数异或为0的性质,两个不为零且不同的数异或运算结果的二进制形式一定有1的性质 解题步骤: 1. 把数组从左到右全部异或运

剑指Offer34 数组中的逆序对

1 /************************************************************************* 2 > File Name: 34_InversePairsInArray.c 3 > Author: Juntaran 4 > Mail: [email protected] 5 > Created Time: 2016年09月02日 星期五 20时05分05秒 6 *******************************

剑指Offer39 数组中寻找和为sum的两个数字

1 /************************************************************************* 2 > File Name: 39_TwoNumbersWithSum.cpp 3 > Author: Juntaran 4 > Mail: [email protected] 5 > Created Time: 2016年09月03日 星期六 11时14分49秒 6 *******************************