【剑指Offer记录】21_调整数组顺序使奇数位于偶数前面

Part1. 我的思路和代码

1-我认为是投机的思路

定义一个与原数组等长的数组,然后从头到尾扫描原数组,依次将奇数填入新数组,再第二次从头到尾扫描原数组,依次将偶数填入新数组。从头到尾扫描原数组、从前向后填充新数组,保证了调整前后奇数、偶数的相对位置不变

扫描两遍数组,每遍时间复杂度都是O(n),总的时间复杂度也为O(n);使用了辅助空间定义了与原数组等长的新数组,空间复杂度为O(n)。

vector<int> reOrderArray(vector<int>& array)
{
    vector<int> ans;
    int idx;

    ans = array;
    idx = 0;
    for(int i=0; i<array.size(); i++){
        if(array[i]%2 != 0){ //奇数
            ans[idx] = array[i];
            ++idx;
        }
    }
    for(int i=0; i<array.size(); i++){
        if(array[i]%2 == 0){ //偶数
            ans[idx] = array[i];
            ++idx;
        }
    }

    return ans;
}

2-片段调整法(不知道起什么标题就这样称了)

遍历数组的每个元素,如果是奇数,则把之前的偶数部分的每个元素都向后移动一个位置,再把该奇数填入“前面空出的那个位置”,如下图所示:

在这里插入图片描述

外层循环遍历数组的每个元素,时间复杂度O(n),内层循环移动一段元素的位置,时间复杂度O(n),总的时间复杂度为O(n^2);使用的额外空间和输入规模无关,空间复杂度为O(1)。

vector<int> reOrderArray(vector<int>& array)
{
    int idx;

    idx = 0; // 指向下一个奇数应该调整到的位置
    for(int i=0; i<array.size(); i++){
        if(array[i]%2 != 0){
            int temp = array[i];
            for(int j=i-1; j>=idx; j--){
                array[j+1] = array[j];
            }
            array[idx] = temp;
            idx++;
        }
    }

    return array;
}

Part2. 其他做法

双指针

定义两个指针p1、p2,初始时分别指向数组第一个、最后一个元素。p1向后移动,遇到偶数停止,p2则向前移动,遇到奇数停止,当p1、p2均停止移动后,交换二者指向的元素,重复该过程,直到p1移动到p2之后。如下图所示:

在这里插入图片描述

该做法至多遍历一次数组,调整操作也是常数时间,时间复杂度为O(n);用到的辅助空间与输入规模无关,空间复杂度为O(1)。

然而,若题目要求调整后奇数、偶数的相对位置不变,则该双指针的做法是不能满足要求的,例如"1 2 3 4 5",第一次调整后2会位于4之后,相对位置发生变化。

Part3. 心得体会

  • 双指针是一个很经典的思路;
  • 调整数组元素需要注意题目是否要求相对位置不变,该要求不同所用的思路也不同;
  • (从书中所学)该题目调整依据是数字的奇偶,若改为其他调整条件则需要修改相应的循环条件,若考虑到代码的扩展性,可以将循环条件抽象为一个函数func(),在函数内部具体实现判断条件,这样当条件变化后只需修改func()即可,无需改动主体代码。
  • 9
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值