【剑指offer】——调整数组中奇数和偶数的位置

一、调整位置不需要相对位置不变

题目要求

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

题目分析

1、版本一
首先一拿到这题我们会立刻迸出一个从头扫描这个数组的思路。每碰到一个偶数,拿出这个数字,并把这个数字后面的所有数字往前挪动一位,这时数组末尾位置就空出来了,再把该偶数插入到数组末尾。但是这个思路仔细想想还是有些不足。因为这样操作的时间复杂度是O(n^2).
2、版本二
我们可以采取交换的策略来解决问题。还是以具体的例子来具体描述一下这个方法,我们拿数组{1,2,3,4,5}来详细说明。
我们首先维护两个指针p1和p2,p1初始化时指向数组的第一个数字,p2初始化时指向数组的最后一个数字,如下图所示:
在这里插入图片描述
要使p1指向偶数,p2指向奇数,两个指针所指向数字的位置。所以p2指向的是奇数5,不需要移动,p1往前移动当p1指向数字2,两个数字交换
在这里插入图片描述
向后移动指针p1,直至他指向偶数4,向前移动指针p2,直至他指向奇数3
在这里插入图片描述
这时候,由于p2已经移动到了p1的前面,表明所有的奇数在偶数的前面了,程序结束。
总结上述过程的重点就在于,p1指向偶数,p1指向奇数的时候,两个指针所指向的数字交换位置;程序结束的条件就是p2指针位于p1指针前面了。

基于上述分析,可以写出我们的代码如下:

void ReorderOddEvent(int* pData, unsigned int length)
{
	if (pData == nullptr || length <= 0)
		return;

	int* p1 = pData;
	int* p2 = pData + length - 1;

	while (p1 < p2)
	{
		//向后移动p1,直至他指向偶数
		while (p1 < p2 && (*p1 & 0x1) != 0)
			p1++;
		
		//向前移动p2,直至他指向奇数
		while (p1 < p2 && (*p2 & 0x1) == 0)
			p2--;

		if (p1 < p2)
		{
			int temp = *p1;
			*p1 = *p2;
			*p2 = temp;
		}
	}
}

3、版本三
上述版本二的方法已经很好的解决了题目中所要求的问题。那么如果是还想让你实现数组中所有负数都在非负数的前面,实现能被3整除的数都在不能被3整除的数前面时你该怎么办呢?如果你只想着改变上述代码中两个while条件即可就有些不妥了。
其实上述代码不具有扩展性。我们可以给出一种模式,在这种模式下能方便的把已有的解决方案扩展到同类型的问题上去。因此,我们可以把上述代码大的框架不动,把整个函数解耦成两个部分:一部分是判断数字应该是在数组的前半部分还是后半部分,二是拆分数组的操作。把判断的标准用函数指针来加以实现。

void Reorder(int* pData, unsigned int length,bool (*func)(int))
{
	if (pData == nullptr || length <= 0)
		return;

	int* p1 = pData;
	int* p2 = pData + length - 1;

	while (p1 < p2)
	{
		//向后移动p1,直至他指向偶数
		while (p1 < p2 && !func(*p1))
			p1++;

		//向前移动p2,直至他指向奇数
		while (p1 < p2 && func(*p2))
			p2--;

		if (p1 < p2)
		{
			int temp = *p1;
			*p1 = *p2;
			*p2 = temp;
		}
	}
}
bool isEven(int n)
{
	return (n & 0x01) == 0;
}
void ReorderOddEven(int* pData, unsigned int length)
{
	Reorder(pData, length, isEven);
}

解耦的好处就是提高了代码的重用性。

二、调整位置需要相对位置不变

题目要求

输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。

题目分析

与上一个问题不同的是,要求改变后的数组相对位置是不变的额,也就是说数组{1,2,3,4,5}移动过后是{1,3,5,2,4}而不是刚刚的{1,5,3,4,2}。

这时,我们可以考虑另外一个空间,新建一个数组先把原数组中的奇数push进去再把偶数push进去,然后用新数组数据覆盖原数组即可。我们使用了vector容器来实现,会更加方便。这样的时间复杂度O(n)。
代码实现如下:

void reOrderArray(vector<int> &array) {
         vector<int> res;
    for (int i = 0; i < array.size(); i++)
    {
        if (array[i] % 2 == 1)
        {
            res.push_back(array[i]);
        }
    }
    for (int i = 0; i < array.size(); i++)
    {
        if (array[i] % 2 == 0)
        {
            res.push_back(array[i]);
        }
    }
    array = res;
        
    }
发布了98 篇原创文章 · 获赞 9 · 访问量 3644

猜你喜欢

转载自blog.csdn.net/qq_43412060/article/details/105448917