首页 > 代码库 > 剑指offer (14) 重组数组使得 奇数在偶数前
剑指offer (14) 重组数组使得 奇数在偶数前
题目描述:
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分
解题分析:
其实就是快速排序的思想. 回想一下快速排序的Partition划分函数,每执行一次划分操作,我们就可以 确定中轴值的最终位置,
也就是 <= 中轴值的所有元素都在 其左边,所有 > 中轴值的元素都在 其右边
我们可以从此获得启发,现在题目要求是 所有奇数在左边,所有偶数在右边, 模拟快速排序的划分操作,我们选取一个 偶数,然后执行划分操作,
执行完划分操作之后,我们可以让 所有奇数都在 左边,所有偶数都在 右边
需要注意:我们选取的中轴值一定要是偶数
1 bool IsEven(int a) 2 { 3 return (a % 2 == 0); 4 } 5 6 typedef bool (*pfunc)(int a, int b); 7 8 bool func(int a, int b) 9 { 10 return (!IsEven(a) && IsEven(b)); 11 } 12 13 14 15 void Partition(std::vector<int>& vec, pfunc func) 16 { 17 if (vec.size() <= 1) return; 18 int midIndex = 0; 19 auto iter = std::find_if(vec.begin(), vec.end(), IsEven); 20 if (iter == vec.end()) { 21 return; 22 } else { 23 std::swap(vec.at(0), *iter); 24 } 25 for (int i = 1; i < vec.size(); ++i) { 26 if (func(vec.at(i), vec.at(0))) { 27 std::swap(vec.at(++midIndex), vec.at(i)); 28 } 29 } 30 std::swap(vec.at(midIndex), vec.at(0)); 31 }
扩展:
1. 需要重排数组,所有负数在前,正数在后. 这个解题思路完全相同,只需要 将 IsEven函数稍稍修改一下 return (a > 0) 即可
1. 需要重排数组,所有能整除3的数在前,不能整除的在后
这个解题思路也是完全相同,只需要 将 IsEven函数稍稍修改一下 return (a % 3 != 0) 即可
我们可以看到 我们需要的仿函数必须满足 处于数组后面的元素的条件要求
相关题:
给定大小为n的数组A,A中的元素有正有负。请给出方法,对其排序,保证:
-
负数在前面,正数在后面
-
正数之间相对位置不变
-
负数之间相对位置不变
能够做到时间复杂度为O(n),空间复杂度为O(1)么?
解题分析:
我们在上一题中,改变了 数组元素之间的相对位置
首先,暴力法可行:从左到右扫描数组,遇到第一个负数,与其前面的每一个元素进行交换,直到第一个位置,这里并不能直接交换,
因为这样就改变了正数的相对位置了。后面的继续扫描,第二个负数,依次交换到第二个位置。依次类推。算法总的时间复杂度为O(n^2)。(其实是插入排序的思想)
上面这个方法,大多数同学,都可以给出。那么,是否有更快的方法呢?大家请看下面的方法:
-
统计负数的个数,设为M
-
找到索引下标 k>= M的第一个负数
-
使用i和j两个索引,i从0开始,直到遇到第一个正数,j从k开始,直到遇到第一个负数。交换i,j位置上的数,然后符号取反
-
对于A[0,M]和A[M, n]分别执行上面三步
-
修正符号:前面的M个为负数,后面的为正数。
下面举例来说明,对于数组{-1,1,3,-2,2},根据描述,有M=2,k=3。i遇到第一个正数为A[1]=1,j遇到第一个负数为A[3]=-2。
然后交换i和j位置上的值, 数组变为{-1, -2, 3, 1, 2}, 然后改变符号,得到{-1,2,3,-1,2}。
然后递归处理{-1,2},{3,-1,2},最终得到{-1,2,1,-3,2}。
进行最后一步,修正符号, 得到{-1,-2,1,3,2}。即为最终答案。
这个方法是nlog(n)的,比上面的提高了一些。
但是上面的方法,仍旧不是O(n)的。那么O(n)的方法,是否存在呢?我们认为,接近O(n)的方法是有的。但是,方法过于复杂。这类问题,可以统称为 stable 0-1 sorting。
大家感兴趣的话,可以参考下面的文章:
http://www.diku.dk/hjemmesider/ansatte/jyrki/Paper/KP92b.pdf
注意:
1. 本题空间复杂度是 O(1),如果没有空间复杂度限制,可以用空间换时间,使用O(n)空间,可以非常容易的在O(n)时间内解决
2. 本题在O(n)时间 O(1)空间的限制下是没有真正的解决方法的,如果存在的话,那么 快速排序就可以是稳定的了