剑指offer 面试题21. 调整数组顺序使奇数位于偶数前面(易)
这个题目的关键,是写出可扩展的代码,本题的要求是使奇数位于偶数前面,那么使负数位于非负数前面,使3的倍数位于3的非倍数前面的功能也要能够直接拓展实现才行。
Question
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。
示例:
1 |
|
注:[3,1,2,4] 也是正确的答案之一。
提示: 1 <= nums.length <= 50000
; 1 <= nums[i] <= 10000
.
测试样例
功能测试(输入数组中的奇数、偶数交替出现;输入的数组中所有偶数都出现在奇数的前面;输入的数组中所有奇数都出现在偶数的前面)。 特殊输入测试(输入 nullptr
指针;输入的数组只包含一个数字)。
考点
考查应聘者的快速思维能力。要在短时间内按照要求把数组分隔成两部分不是一件容易的事情,需要较快的思维能力。 对于已经工作了几年的应聘者,面试官还将考查其对扩展性的理解,要求应聘者写出的代码具有可重用性。
Intuition
暴力破解
从头扫描这个数组,每碰到一个偶数,拿出这个数字,并把位于这个数字后面的所有数字往前挪动一位。挪完之后在数组的末尾有一个空位,这时把该偶数放入这个空位。由于每碰到一个偶数就需要移动 \(O(n)\) 个数字,因此总的时间复杂度是 \(O(n^2)\)。但是,这种方法不能让面试官满意。不过如果我们在听到题目之后能马上说出这种解法,那么面试官至少会觉得我们的思维非常敏捷。通过修改 func
函数可以是随意调整前移条件,实现代码的可扩展性。
双指针
实际上就是快排。
因此,我们可以维护两个指针:第一个指针初始化时指向数组的第一个数字,它只向后移动;第二个指针初始化时指向数组的最后一个数字,它只向前移动。在两个指针相遇之前,第一个指针总是位于第二个指针的前面。如果第一个指针指向的数字是偶数,并且第二个指针指向的数字是奇数,则交换这两个数字。 下面以一个具体的例子,如输入数组{1,2,3,4,5}来分析这种思路。在初始化时,把第一个指针指向数组第一个数字1,而把第二个指针指向最后一个数字5,如图3.6(a)所示。第一个指针指向的数字1是一个奇数,不需要处理,我们把第一个指针向后移动,直到碰到一个偶数2。此时第二个指针已经指向了奇数,因此不需要移动。此时两个指针指向的位置如图3.6(b)所示。这时候我们发现偶数2位于奇数5的前面,符合交换条件,于是交换这两个指针指向的数字,如图3.6(c)所示。 接下来我们继续向后移动第一个指针,直到碰到下一个偶数4,并向前移动第二个指针,直到碰到第一个奇数3,如图3.6(d)所示。我们发现第二个指针已经在第一个指针的前面了,表示所有的奇数都已经在偶数的前面了。此时的数组是{1,5,3,4,2},的确是奇数位于数组的前半部分而偶数位于数组的后半部分。通过修改 func
函数可以是随意调整前移条件,实现代码的可扩展性。

Code
- 暴力破解
1 |
|
- 双指针
1 |
|
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!