文章目录
- 题目
- 思路
- 相对位置可以改变的思路
- 相对位置不能改变的思路
题目
题目链接入口:调整数组顺序使奇数位于偶数前面
示例1:
输入:[1,2,3,4,5,6]
结果:[1,3,5,2,4,6]
示例2:
输入:[1,2,2,3,4,4,5,6,7]
结果:[1,3,5,7,2,2,4,4,6]
思路
1.核心考点:数组操作,排序(插入排序)思想的扩展使用
2.原题变形:这道题目加了一个条件:要求相对位置不变。这里先讲讲相对位置可以改变的情况,这样能更好的理解“什么叫相对位置不变”。
相对位置可以改变的思路
(1)使用双(头尾)指针法,一个指向数组的第一个元素,一个指向数组的最后一个元素。
(2)当begin指向的元素是偶数,begin停下,当end指向的元素是奇数,end也停下,然后交换begin和end指向的元素。
(3)注意临界条件:我们不仅要在最外层循环添加条件begin<end,在begin++,end–的过程中,我们也要保持begin<end
大家可以发现,[1,2,3,4,5,6]若相对位置可以发生改变,得到的结果是[1,5,3,4,2,6],原来3本来在5的前面,结果5在交换过后,跑到3前面去了,那么这就是相对位置发生改变。
若要求相对位置不变,结果是[1,3,5,2,4,6](示例中),结果3依然是在5前面的,保持了相对位置不发生改变。
这种方法的代码如下:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class Solution {
public:
void reOrderArray(vector<int> &array) {
if (array.size() == 0)
{
return;
}
int begin = 0;
int end = array[array.size() - 2];
while (begin < end)
{
while (begin < end&&array[begin] & 1)//是奇数则++,遇到偶数才停下
{
begin++;
}
while (begin < end && (!(array[end] & 1)))//是偶数则--,遇到奇数才停下
{
end--;
}
//交换
if(begin < end)
{
swap(array[begin], array[end]);
}
}
}
};
int main()
{
Solution s;
vector<int> array{ 1,2,3,4,5,6};
s.reOrderArray(array);
return 0;
}
相对位置不能改变的思路
(1)这道题的关键点在于:奇数要位于偶数前面,并且!奇数偶数的相对位置相较于原数组的顺序不能发生改变。
(2)采用插入排序的思想:找到奇数依次插入到前面,偶数整体后移。
定义i=0,用于遍历原数组(找到奇数),然后用tmp临时变量保留奇数tmp=array[i]
,遍历找到的第一个奇数肯定放在下标为0的位置,第二个奇数肯定放在下标为1的位置,所以我们还要定义一个变量k,去记录已经插入的奇数的位置array[k++]=tmp
(用于将奇数前插置k下标位置处,这种做法就保证了奇数的相对位置不会改变)。那么偶数如何做到整体后移,不改变相对位置的顺序呢?
由于i用来遍历数组,所以i不能被改变,我们用变量j进行操作,使j=i
,这个时候array[j]
是我们找到的奇数,现在前面的偶数整体向后移动,即array[j]=array[j-1]
,也就是说我们当前找到的奇数就被覆盖了(这个操作也保证了偶数的相对位置不发生改变),这也正是我们为什么要用临时变量tmp保存奇数的原因。
解释代码的两个点
1.我们用array[i]&1
来判断是否是奇数,原因在于二进制序列的第一位是2的0次方就是1,其它位置都是偶数,所以若第一位是1,那么这个数必是奇数。
2.偶数后移的循环条件
j>k
:由于k记录奇数已经插入的奇数的位置,所以j必须>k,保证前面已经调整好的奇数不被影响。
建议大家通过编译器调试窗口对各个变量进行解读,通过监视窗口,以及各个变量的变化,更能看出奇数前插,偶数整体后移的过程。我在这里大概写一下。
代码如下:
C++版本:
class Solution {
public:
void reOrderArray(vector<int> &array) {
if(array.size()==0)
{
return;
}
int k=0;//用于前插奇数
int j=0;
for(int i=0;i<array.size();i++)//
{
if(array[i]&1)//奇数的二进制最后一位是1
{
j=i;//i不能被改变,所以用j
int tmp=array[i];//保留奇数,前插置k下标位置处
while(j>k)//必须保证j>k,否则就会破坏已经排好的奇数序列
{
array[j]=array[j-1];//偶数整体后移
j--;
}
array[k++]=tmp;
}
}
}
};
java版本:
public class Solution {
public void reOrderArray(int [] array) {
int k = 0;
for (int i = 0; i < array.length; i++) {
if ((array[i] & 1) ==1) { //从左向右,每次遇到的,都是最前面的奇数,一定将来要被放在k下标处
int temp = array[i];//现将当前奇数保存起来
int j = i;
while (j > k) { //将该奇数之前的内容(偶数序列),整体后移一个位置
array[j] = array[j - 1];
j--;
}
array[k++] =temp;//将奇数保存在它将来该在的位置,因为我们是从左往右放的,没有跨越奇数,所以一定是相对位置不变的
}
}
}
}