题目:
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。
第一思路时间复杂度O(n^2):
看到这个题,我的脑海里就浮现了一个时间复杂度为O(n^2)的算法。即从头扫描这个数组,每碰到一个偶数时,拿出这个数字,并把位于这个数字后面的所有数字往前挪动一位。挪完之后在数组的末尾就有一个空位,这时把该偶数放入这个空位,但是要在此位置(刚刚被移走偶数所在的位置)重新判断一次。由于每次碰到一个偶数就需要移动O(n)个数字,因此这个算法的时间复杂度为O(n^2)。
实现代码:
public void reorderOddEven(int []number){ if(number == null && number.length == 0){ return; } int len = number.length; //存储数组长度 int count = 0; //控制数组遍历的循环次数 for (int i = 0; i < len && count < len; ++i) { // ++count; int temp = number[i]; if((temp & 0x1) == 0){ //如果为偶数,移动数组,将数放入数组末尾,并使i在i-1的位置,重新开始判断 for (int j = i; j < len-1; ++j) { number[j] = number[j+1]; } number[len-1] = temp; --i; } } }
优化代码:
public void reorderOddEven2(int []number){ if(number == null && number.length == 0){ return; } for (int i = 0, j = 0; i < number.length; ++i) { if((number[i] & 0x1) != 0){ int temp = number[i]; number[i] = number[j]; number[j] = temp; ++j; } } }
优化思路:
我们可以利用两个指针,来优化这个题的解法。第一个指针p1初始化时指向数组的第一个数字即number[0],它只向后移动;第二个指针初始化时指向数组的最后一个数字即number[number.length-1],它只向前移动。在两个指针相遇之前,第一个指针总是位于第二个指针的前面。如果第一个指针指向的数字是偶数,并且第二个指针指向的数字是奇数,我们就交换这两个数字。
代码实现:
public void reorderOddEven1(int []number){ int len = number.length; if(number == null || len == 0){ return; } int begin = 0; int end = len -1; while(begin < end){ while((begin < end) && (number[begin] & 0x1) != 0){ ++begin; } while((begin < end) && (number[end] & 0x1) == 0){ --end; } if(begin < end){ int temp = number[begin]; number[begin] = number[end]; number[end] = temp; } } }
拓展:
把题目改成把数组中的数按照大小分为两部分,所有的负数都在非负数的前面;
把题目改成把数组中的数按照能不能被3整除分为两部分,所有不能被3整除的数在前面。
上面的两个题目其实它的意图很明显,想让我们把我们上面的函数解耦成两部分:一是判断数字应该在数组前半部分还是后半部分的标准;二是拆分数组的操作。
public boolean isEven(int num){ if((num & 0x1) == 0){ return true; }else{ return false; } }
public boolean isDivideBy3(int num){ if(num % 3 == 0){ return true; }else{ return false; } }
public boolean isNonnegativeNumber(int num){ if(num >= 0){ return true; }else{ return false; } }
public void reorder(int []number){ int len = number.length; if(number == null || len == 0){ return; } int begin = 0; int end = len -1; while(begin < end){ while((begin < end) && 方法){ ++begin; } while((begin < end) && 方法){ --end; } if(begin < end){ int temp = number[begin]; number[begin] = number[end]; number[end] = temp; } } }
小思:
需要由一道题延伸到一类型题。