面试题21:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
方法一:数组的引用作为实参O(N)
class Solution {
public:
void reOrderArray(vector<int> &array) { //需要对数组进行修改,故数组引用组为形参
vector<int> result;
int length = array.size();
for (int i = 0; i <length; ++i){
if (array[i] & 0x1 == 1)
result.push_back(array[i]);
}
for (int i = 0; i <length; ++i){
if((array[i] & 0x1) == 0) //(array[i] & 0x1)此处不加括号则报错
result.push_back(array[i]);
}
array = result;
}
};
方法二:使用指针作为形参
class Solution {
public:
void reOrderArray(int *pData, unsigned int length)
{
if(pData == nullptr || length == 0)
return;
int *pBegin = pData;
int *pEnd = pData + length - 1;
while(pBegin < pEnd)
{
// 向后移动pBegin,直到它指向偶数
while(pBegin < pEnd && (*pBegin & 0x1) != 0)
pBegin ++;
// 向前移动pEnd,直到它指向奇数
while(pBegin < pEnd && (*pEnd & 0x1) == 0)
pEnd --;
if(pBegin < pEnd)
{
int temp = *pBegin;
*pBegin = *pEnd;
*pEnd = temp;
}
}
}
};
方法三:函数指针实现通用性
我们可以把这个逻辑框架抽象出来, 而把判断的标准变成 个函数指针, 也就是用一个单独的函数来判断数字是不是符合标准。 这样我们就把整个函数解糊成两部分:一是判断数字应该在数组前半部分还是后半部分的标准; 二是拆分数组的操作。
在下面的代码中,函数Reor由r根据func的标准把数组pData分成两部 分: 而函数isEven则是一个具体的标准, 即判断一个数是不是偶数。 有了这两个函数, 我们就可以很方便地把数组中的所有奇数移到偶数的前面。解耦的好处就是提高了代码的重用性,为功能扩展提供了便利。
class Solution{
public:
void ReorderOddEven_2(int *pData, unsigned int length)
{
Reorder(pData, length, isEven); //isEven函数名称代表地址
}
void Reorder(int *pData, unsigned int length, bool (*func)(int))
{
if(pData == nullptr || length == 0)
return;
int *pBegin = pData;
int *pEnd = pData + length - 1;
while(pBegin < pEnd)
{
// 向后移动pBegin
while(pBegin < pEnd && !func(*pBegin))
pBegin ++;
// 向前移动pEnd
while(pBegin < pEnd && func(*pEnd))
pEnd --;
if(pBegin < pEnd)
{
int temp = *pBegin;
*pBegin = *pEnd;
*pEnd = temp;
}
}
}
bool isEven(int n)
{
return (n & 1) == 0;
}
};