索引请参考:系列目录
题目:
- 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分
- 示例:
- 输入:2,1,4,9,7,6,3,5,8
- 输出:1,9,7,3,5,2,4,6,8
分析:
- 将本题分为两种思维模式:人对数组进行排列的模式和机器对数组进行排列的模式
- 人对数组进行排列的模式:看到一组数,从前往后进行依次对比然后进行排序
- 机器对数组进行排列的模式:双指针进行快速比较排序
思路1:
- 遍历数组,若数组为偶数,则元素的位置不变
- 若数组为奇数
- 向前访问一位
- 若前一位是偶数,交换位置
- 否则跳出比较语句(此处精髓:while语句 其作用是 当数组判断到有奇数时,向前访问一位,若此时前一位为偶数,而前一位的前一位也为偶数…以此类推,均需要进行对前面的所有偶数将进行交换位置)
- 若数组为奇数
思路2:
- 维护两个指针
- 第一个指针初始化时指向数组的第一个数字,它只向后一定
- 第二个指针初始化时指向数组的最后一位,它只向前移动
- 条件1:在2个指针相遇之前,第一个指针总是位于第二个指针的前面
- 条件2:如果指针指向的数组是偶数,并且第二个指针指向的数字是奇数,则交换这两个数字
思路1:
void reOrderArray(std::vector<int> &array) {
int size = array.size();
for (int i = 0; i < size; i++)
{
while (array[i] % 2 == 1)
{
if (i - 1 >= 0 && array[i - 1] % 2 == 0)
{
int temp = array[i];
array[i] = array[i - 1];
array[i - 1] = temp;
--i;
}
else
break;
}
}
}
思路2:
void reOrderArray(vector<int> &array) {
int begin = 0;
int end = array.size() - 1;
while (begin < end)
{
while (begin < end && array[begin] % 2 == 1)
++begin;
while (begin < end && array[end] % 2 == 0)
--end;
if (begin < end)
{
int temp = array[begin];
array[begin] = array[end];
array[end] = temp;
}
}
}
上述代码中。方法1可以通过牛客的检测因为牛客中题目比剑指offer的题目更加苛刻:
方法2没有通过,原因是该方法没有办法保证调整数组位置后技术和偶数之间的相对位置不发生改变
方法2的演化版本:该方法用了一些迭代器的知识
void reOrderArray1(std::vector<int> &array) {
auto begin = array.begin();
auto end = array.end() - 1;
while (begin < end)
{
while (begin < end && *begin % 2 == 1)
++begin;
while (begin < end && *end % 2 == 0)
--end;
if (begin < end)
{
int temp = *begin;
*begin = *end;
*end = temp;
}
}
}
评注:虽然方法二因为牛客的题目更加苛刻导致没有完全通过,但是我们可以借鉴双指针的思想去解决以一些问题。比如排序算法中的希尔排序等都或多或少用到这种思想。