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);
        }
    };
  • 相关阅读:
    Leetcode Substring with Concatenation of All Words
    Leetcode Divide Two Integers
    Leetcode Edit Distance
    Leetcode Longest Palindromic Substring
    Leetcode Longest Substring Without Repeating Characters
    Leetcode 4Sum
    Leetcode 3Sum Closest
    Leetcode 3Sum
    Leetcode Candy
    Leetcode jump Game II
  • 原文地址:https://www.cnblogs.com/lightmare/p/10398759.html
Copyright © 2011-2022 走看看