zoukankan      html  css  js  c++  java
  • 第21题:调整数组顺序使奇数位于偶数前面

    第一题

    题目描述

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

    方法一 

    第一遍

    void ReorderOddEven_1(int *pData, unsigned int length)
    {
    	//1.如果数组为nullptr,长度为0,返回
    	if (!pData&&length == 0)
    		return;
    	//2.设定两个指针,第一个指向偶数,初始值是第一个,第二个总指向奇数,初始值是最后一个
    	int* even = pData;
    	int* odd = pData + length - 1;
    	
    	//3.循环条件:当偶数指针在奇数指针前面时
    	while (even < odd)
    	{
    		//3.1 如果第一个不指向偶数,往后移一个指针
    		while (even < odd && (*even & 0x1) != 0)//0x1是零,不是欧
    			even++;
    
    		//3.2 如果第二个指针不指向奇数,往前移一个指针
    		while (even < odd && (*odd & 0x1) != 1)
    			odd--;
    
    		//3.3 如果奇数在偶数前面,交换两个指针的值
    		if (even < odd)
    		{
    			int temp = *even;
    			*even = *odd;
    			*odd = temp;
    		}
    	}
    }

     第二遍

    class Solution {
    public:
        void reOrderArray(vector<int> &array) {
            //1.记录数组长度
            int length = array.size();
            //2.如果数组为nullptr,或者长度为0,返回
            if(length == 0)
                return ;
            //3.设置两个指针,even指向偶数指针,odd指向奇数指针,偶数指针在奇数指针前面
            int* even = &array[0];
            int* odd = &array[length-1];
            
            //4.while even在odd前面时
            while(even<odd)
            {
                //4.1 如果even没有指向偶数,则往后移动一个
                while(even<odd&&(*even & 0x1)!=0)
                    even++;
                    
                //4.2 如果odd没有指向奇数,则向前移动一个
                while(even<odd&&(*odd & 0x1)!=1)
                    odd--;
                
                //4.3 如果偶在奇前,交换奇偶指针
                if(even<odd)
                {
                    int temp=*even;
                    *even = *odd;
                    *odd=temp;
                }
            }
            
        }
    };

    方法二:解耦

    将代码分为两个部分:操作、标准。

    解耦提高代码的重用性,因为标准可能不一样,但是总体设计架构是不变的。

     

    void ReorderOddEven_2(int *pData, unsigned int length)
    {
    	//Reorder(int *pData, unsigned int length, bool(*func)(int))
    	//函数参数,直接传递函数名,
    	return Reorder(pData,length,isEven);
    }
    void Reorder(int *pData, unsigned int length, bool(*func)(int))
    {
    	//1.如果数组为nullptr,长度为0,返回
    	if (!pData&&length == 0)
    		return;
    	//2.设定两个指针,第一个指向偶数,初始值是第一个,第二个总指向奇数,初始值是最后一个
    	int* even = pData;
    	int* odd = pData + length - 1;
    
    	//3.循环条件:当偶数指针在奇数指针前面时
    	while (even < odd)
    	{
    		//3.1 如果第一个不指向偶数,往后移一个指针
    		while (even < odd && !func(*even))//0x1是零,不是欧
    			even++;
    
    		//3.2 如果第二个指针不指向奇数,往前移一个指针
    		while (even < odd && func(*odd))
    			odd--;
    
    		//3.3 如果奇数在偶数前面,交换两个指针的值
    		if (even < odd)
    		{
    			int temp = *even;
    			*even = *odd;
    			*odd = temp;
    		}
    	}
    }
    //是否为偶数
    bool isEven(int n)
    {
    	return (n & 1) == 0 ;//要加括号,不然一直是false
    }

    补一下优先级的知识

    C++ 

    运算符

    描述

    例子

    可重载性

    第一级别

         

    ::

    作用域解析符

    Class::age = 2;

    不可重载

    第二级别

         

    ()

    函数调用

    isdigit('1')

    可重载

    ()

    成员初始化

    c_tor(int x, int y) : _x(x), _y(y*10){};

    可重载

    []

    数组数据获取

    array[4] = 2;

    可重载

    ->

    指针型成员调用

    ptr->age = 34;

    可重载

    .

    对象型成员调用

    obj.age = 34;

    不可重载

    ++

    后自增运算符

    for( int i = 0; i < 10; i++ ) cout << i;

    可重载

    --

    后自减运算符

    for( int i = 10; i > 0; i-- ) cout << i;

    可重载

    const_cast

    特殊属性转换

    const_cast<type_to>(type_from);

    不可重载

    dynamic_cast

    特殊属性转换

    dynamic_cast<type_to>(type_from);

    不可重载

    static_cast

    特殊属性转换

    static_cast<type_to>(type_from);

    不可重载

    reinterpret_cast

    特殊属性转换

    reinterpret_cast<type_to>(type_from);

    不可重载

    typeid

    对象类型符

    cout &laquo; typeid(var).name();

    cout &laquo; typeid(type).name();

    不可重载

    第三级别(具有右结合性)

         

    !

    逻辑取反

    if( !done ) …

    可重载

    not

    ! 的另一种表达

       

    ~

    按位取反

    flags = ~flags;

    可重载

    compl

    ~的另一种表达

       

    ++

    预自增运算符

    for( i = 0; i < 10; ++i ) cout << i;

    可重载

    --

    预自减运算符

    for( i = 10; i > 0; --i ) cout << i;

    可重载

    -

    负号

    int i = -1;

    可重载

    +

    正号

    int i = +1;

    可重载

    *

    指针取值

    int data = *intPtr;

    可重载

    &

    值取指针

    int *intPtr = &data;

    可重载

    new

    动态元素内存分配

    long *pVar = new long;

    MyClass *ptr = new MyClass(args);

    可重载

    new []

    动态数组内存分配

    long *array = new long[n];

    可重载

    delete

    动态析构元素内存

    delete pVar;

    可重载

    delete []

    动态析构数组内存

    delete [] array;

    可重载

    (type)

    强制类型转换

    int i = (int) floatNum;

    可重载

    sizeof

    返回类型内存

    int size = sizeof floatNum;

    int size = sizeof(float);

    不可重载

    第四级别

         

    ->*

    类指针成员引用

    ptr->*var = 24;

    可重载

    .*

    类对象成员引用

    obj.*var = 24;

    不可重载

    第五级别

         

    *

    乘法

    int i = 2 * 4;

    可重载

    /

    除法

    float f = 10.0 / 3.0;

    可重载

    %

    取余数(模运算)

    int rem = 4 % 3;

    可重载

    第六级别

         

    +

    加法

    int i = 2 + 3;

    可重载

    -

    减法

    int i = 5 - 1;

    可重载

    第七级别

         

    <<

    位左移

    int flags = 33 << 1;

    可重载

    >>

    位右移

    int flags = 33 >> 1;

    可重载

    第八级别

         

    <

    小于

    if( i < 42 ) …

    可重载

    <=

    小于等于

    if( i <= 42 ) ...

    可重载

    >

    大于

    if( i > 42 ) …

    可重载

    >=

    大于等于

    if( i >= 42 ) ...

    可重载

    第九级别

         

    ==

    恒等于

    if( i == 42 ) ...

    可重载

    eq

    == 的另一种表达

       

    !=

    不等于

    if( i != 42 ) …

    可重载

    not_eq

    !=的另一种表达

       

    第十级别

         

    &

    位且运算

    flags = flags & 42;

    可重载

    bitand

    &的另一种表达

       

    第十一级别

         

    ^

    位异或运算

    flags = flags ^ 42;

    可重载

    xor

    ^的另一种表达

       

    第十二级别

         

    |

    位或运算

    flags = flags | 42;

    可重载

    bitor

    |的另一种表达

       

    第十三级别

         

    &&

    逻辑且运算

    if( conditionA && conditionB ) …

    可重载

    and

    &&的另一种表达

       

    第十四级别

         

    ||

    逻辑或运算

    if( conditionA || conditionB ) ...

    可重载

    or

    ||的另一种表达

       

    第十五级别(具有右结合性)

         

    ? :

    条件运算符

    int i = (a > b) ? a : b;

    不可重载

    第十六级别(具有右结合性)

         

    =

    赋值

    int a = b;

    可重载

    +=

    加赋值运算

    a += 3;

    可重载

    -=

    减赋值运算

    b -= 4;

    可重载

    *=

    乘赋值运算

    a *= 5;

    可重载

    /=

    除赋值运算

    a /= 2;

    可重载

    %=

    模赋值运算

    a %= 3;

    可重载

    &=

    位且赋值运算

    flags &= new_flags;

    可重载

    and_eq

    &= 的另一种表达

       

    ^=

    位异或赋值运算

    flags ^= new_flags;

    可重载

    xor_eq

    ^=的另一种表达

       

    |=

    位或赋值运算

    flags |= new_flags;

    可重载

    or_eq

    |=的另一种表达

       

    <<=

    位左移赋值运算

    flags <<= 2;

    可重载

    >>=

    位右移赋值运算

    flags >>= 2;

    可重载

    第十七级别

         

    throw

    异常抛出

    throw EClass(“Message”);

    不可重载

    第十八级别

         

    ,

    逗号分隔符

    for( i = 0, j = 0; i < 10; i++, j++ ) …

    可重载

     补一下函数指针

    函数指针


    第二题

    相对位置不变

    方法一:插入排序

    class Solution {
    public:
        void reOrderArray(vector<int> &array) {
            //1.读取容器size
            int length = array.size();
            //2.如果容器大小为0,返回
            if (length == 0)
                return;
            
            //3.偶数下标从0开始
            int peven = 0;
            //4.找到第一个偶数
            while (peven < length && (array[peven] &1))
                peven++;
            //5.如果没有偶数,返回
            if (peven == length)
                return;
            
            
            //6.奇数从下标为0开始
            int podd = 0;
            
            //7.如果奇数小于长度
            while (podd < length) 
            {
                //7.1 找第一个奇数
                while (podd < length && !(array[podd]&1))
                    podd++;
                //7.2 如果没有找到奇数,返回
                if (podd == length)
                    return;
                //7.3 如果奇数在偶数后面:将偶数后面&&奇数前面的所有数 全部 向后移一位,并将偶数指针向后移动一位
                if (podd > peven) 
                {
                    //7.3.1 保存奇数的值
                    int temp = array[podd];
                    //7.3.2 从奇数开始,将前一位的数复制到这一位,直到到达偶数指针的位置
                    for (int i = podd; i>peven; i--) 
                    {
                        array[i] = array[i - 1];
                    }
                    //7.3.3 将偶数位置的数 赋值为 奇数的值。
                    array[peven] = temp;
                    //7.3.4 偶数的下标+1
                    peven++;
                }
                //8.奇数指针向后移动一位
                podd++;
            }
            
            return;
        }
    }; 

    方法二:vector内部的代码erase,复杂度O(n^2)

    STL std::vector::erase的用法

    语法

    iterator erase (const_iterator position);
    iterator erase (const_iterator first, const_iterator last);

    例子

    // erasing from vector
    #include <iostream>
    #include <vector>
    
    int main ()
    {
      std::vector<int> myvector;
    
      // set some values (from 1 to 10)
      for (int i=1; i<=10; i++) myvector.push_back(i);
    
      // erase the 6th element
      myvector.erase (myvector.begin()+5);
    
      // erase the first 3 elements:
      myvector.erase (myvector.begin(),myvector.begin()+3);
    
      std::cout << "myvector contains:";
      for (unsigned i=0; i<myvector.size(); ++i)
        std::cout << ' ' << myvector[i];
      std::cout << '
    ';
    
      return 0;
    }

    将偶数从数组中擦去,然后再push到数组尾部 

    class Solution {
    public:
        void reOrderArray(vector<int> &array)
        {
            //1.偶数迭代器,从头开始
            vector<int>::iterator even = array.begin();
            //2.读取数组长度。
            int size = array.size();
            //3.如果长度不为空
            while (size)
            {
                //3.1 如果为偶数
                if (!(*even &1))
                {
                    //3.1.1 将偶数保存
                    int tmp = *even;
                    //3.1.2 从数组中去掉这个偶数
                    even = array.erase(even);
                    //3.1.3 将偶数push到数组尾部
                    array.push_back(tmp);
                }
                //3.2 否则,下标+1
                else
                    even++;
                //4.需要判断的字符-1
                size--;
            }
        }
    };

    方法三:利用空间换时间,复杂度是O(n)+O(n) = O(n)

    思想:

    新建一个数组保存结果,从前往后遍历两次,第一遍找奇数,第二遍找偶数。

    class Solution {
    public:
        void reOrderArray(vector<int> &array) {
            //1.新建一个容器存放 结果
            vector<int> result;
            //2.保存数组长度
            int num=array.size();
            //3.从前往后遍历,找奇数
            for(int i=0;i<num;i++)
            {
                //3.1 如果是奇数,放入result数组中
                if(array[i]&1)
                    result.push_back(array[i]);
            }
            //4.从前往后遍历,找偶数
            for(int i=0;i<num;i++)
            {
                //4.2 如果是偶数,放入result数组中
                if(!(array[i]&1))
                    result.push_back(array[i]);
            }
            //5.更新数组
            array=result;
        }
    };

    方法四:STL

    用的STL stable_partition 这个函数

    函数功能是将数组中 isOk为真的放在数组前,假的放在数组后,和题意相符

    bool isOk(int n)
    {  
    return (n & 1) == 1; 
    //奇数返回真 
    }
    
    class Solution
    {
        void reOrderArray(vector<int> &array)
        {
            stable_partition(array.begin(),array.end(),isOk);
        }
    };
  • 相关阅读:
    chrome的console功能
    vue-cli · Failed to download repo vuejs-templates/webpack: connect ETIMEDOUT 13.229.188.59:443
    let const区别!
    字符串拼接事故!
    git常用的操作命令
    vue项目中利用popstate处理页面返回操作
    Mac下安装nginx并配置SSL实现Https的访问
    浏览器缓存
    HTTP相关知识点
    CORS请求
  • 原文地址:https://www.cnblogs.com/lightmare/p/10398759.html
Copyright © 2011-2022 走看看