剑指offer_t13_调整数组顺序使奇数位于偶数前面

本文介绍了如何使用暴力法、双指针法和STL中的partition函数对数组进行特定条件的排序。针对牛客网和LeetCode的不同题目需求,分别提供了满足有序和无序要求的解决方案,并详细探讨了partition函数及其与stable_partition函数的区别,包括lamda表达式的使用。此外,文章还指出了在使用成员函数作为筛选原则时需要注意的编译错误问题。
摘要由CSDN通过智能技术生成


在这里插入图片描述
注意,这里牛客上和leetcode上的题目略有不同,导致部分解法不一样;牛客上的题目要保证奇书和偶数是有序的,略难于leetcode。

1 暴力法

很直接的思路,找出奇数元素和偶数元素并分别存放到各自数组中;之后再先存奇数,后存偶数。麻烦

class Solution {
public:
    vector<int> reOrderArray(vector<int>& array) {
        // write code here
        vector<int> v1;
        vector<int> v2;
        if(array.empty()) return v1;
        for(int i = 0; i<array.size();i++)
        {
            if(array[i]%2==1)
                v1.push_back(array[i]);
            else if(array[i]%2==0)
                v2.push_back(array[i]);
        }
        vector<int> v;
        for(int i = 0; i<v1.size();i++)
            v.push_back(v1[i]);
        for(int i = 0; i<v2.size();i++)
            v.push_back(v2[i]);
        return v;
    }
};

2 双指针法

对于leetcode上的解法,采用双指针即可,解法参考
在这里插入图片描述

vector<int> exchange(vector<int>& array) {
    if(array.empty()) return array;
    int i = 0;
    int j = array.size()-1;
    vector<int> v;
    while(i<j)
    {
        if(array[i]%2==1 && array[j]%2==0) //奇-偶
        {   i++;
            j--;
        }

        else if(array[i]%2==0 && array[j]%2==1) //偶-奇
        {
            int t = array[i];
            array[i] = array[j];
            array[j] = t ;
            i++;
            j--;
        }
        else if (array[i]%2==1) //奇奇 //左边符合条件,左++
        {
            i++;
        }
        else  //偶偶 右边符合条件,右--
        {
            j--;
        }
    }
    return array;
}

对于牛客上的解法,因为有序要求,上述方法不满足,但仍可以采用双指针思路。
即,左指针从前往后找,找到奇数就顺序放到新数组v中,右指针从后往前找,找到偶数倒序放到新数组v中;

class Solution {
public:
    vector<int> reOrderArray(vector<int>& array) {
        if(array.empty()) return array;
        int head = 0;
        int tail = array.size()-1;
        int l=0;
        int r=array.size()-1;
        vector<int> v(array.size());
        while(l<array.size()&&r>=0)
        {
            if(array[l]%2==1)
            {
                v[head] = array[l];
                head++;
            }
            l++;
            if(array[r]%2==0)
            {
                v[tail] = array[r];
                tail--;
            }
            r--;
        }
        return v;
    }
};

3 STL中的partition()函数

这个我在刷题中还是第一次遇到,期间又遇到了许多问题,在这里尽可能的总结一下。

3.1 partition() 和stable_ partition() 简介

参考C++ partition()和stable_partition()函数详解
函数原型:partition(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred)
其中,[first, last] 确定函数的作用范围,frst和last都是前向迭代器,pred是一种筛选原则。

1). partition可译为分组,即把指定区域类的数据按照 筛选原则分为两组,第一组满足该原则,第二组不满足该原则。partition函数并不关心原数据之间的相对位置,如果想要分组后元素的相对位置不改变,可使用stable_ partition(),函数原型类似。
2). 筛选原则,官网上给的解释,
在这里插入图片描述
本质是一个接收一个参数且返回值为bool类型,例如把数组中奇数和偶数找出来,筛选规则可以为输出参数为数组元素值,返回值为是否为奇数,可以是普通函数,可以是函数对象,也可以是lamda表达式
3). 另外,partition() 函数还会返回一个前向迭代器,指向两部分分界的位置,具体来说是指向第二部分的第一个元素。

3.2刷题遇到的问题

1.普通函数和类的成员函数

class Solution {
public:
     bool com(int i){
        return (i%2)==1;
    }
     vector<int> reOrderArray(vector<int>& array) {
     stable_partition(array.begin(), array.end(),com);
     return array;  
    }
};

上述代码无法通过编译,错误如下
在这里插入图片描述
在者之前我们要分清楚两个概念,普通函数(我也不知道应不应该这样叫)和类的成员函数,
类的成员函数都默认会有this指针这个参数,判断奇数时表面上只用到一个参数,实际上是两个,出现了形参与实参不匹配的情况。这里在类成员函数前加上static关键字或者移除使之成为普通函数。

3.3. lamda表达式

参考:C++11 lambda匿名函数用法详解
c++11中引入了lamda表达式,其语法形式为

[外部变量访问方式说明符] (参数) mutable noexcept/throw() -> 返回值类型
{
   函数体;
};

同理于maltab的@匿名表达式,
1)[] 表示当前是一个lamda表达式,里面可以注明使用哪些外部变量;
2)() 函数形参;
3)mutable noexcept/throw()等可省略。
。。。。。
ladma函数优点,可以就地匿名定义目标函数或者目标对象,可读性和维护性更高;且实现闭包。
上述程序可改为

class Solution {
public:    
      vector<int> reOrderArray(vector<int>& array) {
      stable_partition(array.begin(), array.end(),[](int i) {return (i%2)==1;});
      return array;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

通信仿真爱好者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值