剑指offer学习笔记 调整数组顺序使奇数位于偶数前面

面试题21:调整数组顺序使奇数位于偶数前面。输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。

如果不考虑时间复杂度,最简单的思路是从头扫描这个数组,每碰到一个偶数,拿出这个数字,并把位于这个数字后面的所有数字往前挪动一位,挪完之后数组的末尾就有一个空位,这时把该偶数放入这个空位。由于每碰到一个偶数就需要移动O(n)个数字,因此总的时间复杂度是O(n²)。

只完成基本功能的解法:这道题目要求把奇数放在数组的前半部分,偶数放在数组的后半部分,因此所有的奇数应该位于偶数的前面。即,我们在扫描这个数组的时候,如果发现有偶数出现在奇数前面,则交换它们的顺序,交换之后就符合要求了。因此,我们可以维护两个指针,第一个指针初始化为指向数组的第一个数字,它只向后移动,第二个指针初始化为指向数组的最后一个数字,它只向前移动,在两个指针相遇之前,第一个指针总是位于第二个指针前面。如果第一个指针指向的是偶数,第二个指针指向的是奇数,则交换这两个数字:

#include <iostream>
using namespace std;

void ReorderOddEven(int nums[], int length) {
    if (nums == nullptr || length <= 0) {
        return;
    }

    int* head = nums;
    int* tail = nums + length - 1;

    while (head != tail) {
        if (*head & 1) {    //当head指向奇数时,检查head指向的下一个数字
            ++head;
        }
        else {    //当head指向偶数时,交换head和tail指向的数字,下一步仍检查head指向的数字,且tail指向的数字已经是偶数,需自减
            int temp = *tail;
            *tail = *head;
            *head = temp;
            --tail;
        }
    }
}

int main() {
    int nums[] = {2,2,2,2,1};
    ReorderOddEven(nums, 5);
    for (int i : nums) {
        cout << i << endl;
    }
    return 0;
}

可扩展性的解法:如面试者是毕业生或初级程序员,面试官会满意以上解法,但如果面试者申请的是资深开发,就需要考虑到程序扩展性,如把负数放到非负数前面等类似问题。要解决这种类似问题,只需要修改函数中的if条件判断,而大的逻辑框架不需要改动,因此我们可以把逻辑框架抽象出来,而把判断的标准变成一个函数指针,即用一个单独的函数来判断数字是不是符合标准。这样我们可以把整个函数解耦成两部分:一是判断数字应该在前半部分还是后半部分的标准,二是拆分数组的操作:

#include <iostream>
using namespace std;

void ReorderOddEven(int nums[], int length, bool (*func)(int)) {
    if (nums == nullptr || length <= 0) {
        return;
    }

    int* head = nums;
    int* tail = nums + length - 1;

    while (head != tail) {
        if (func(*head)) {    //当head指向奇数时,检查head指向的下一个数字
            ++head;
        }
        else {    //当head指向偶数时,交换head和tail指向的数字,下一步仍检查head指向的数字,且tail指向的数字已经是偶数,需自减
            int temp = *tail;
            *tail = *head;
            *head = temp;
            --tail;
        }
    }
}

bool isEven(int num) {
    return num & 1;
}

int main() {
    int nums[] = {2,2,2,2,1};
    ReorderOddEven(nums, 5, isEven);
    for (int i : nums) {
        cout << i << endl;
    }
    return 0;
}

这样类似问题只需要定义新的判断分组标准的函数而不需要对Reorder进行任何改动。即解耦好处是提高了代码的重用性,为功能扩展提供了便利。

发布了193 篇原创文章 · 获赞 11 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/tus00000/article/details/104483762
今日推荐