题⽬描述

输⼊⼀个⻓度为 n 整数数组,数组⾥⾯不含有相同的元素,实现⼀个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前⾯部分,所有的偶数位于数组的后⾯部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。

示例1

输⼊:[1,2,3,4]

返回值:[1,3,2,4]

示例2

输⼊:[2,4,6,5,7]

返回值:[5,7,2,4,6]

示例3

输⼊:[1,3,5,6,7]

返回值:[1,3,5,7,6]

思路及解答

空间换时间(辅助数组)

通过创建两个临时数组分别存储奇数和偶数,然后合并它们。这种方法简单易懂,但需要额外的空间。

新建⼀个数组, copy ⼀份,先计算出奇数的个数,也就是能够知道第⼀个偶数应该放在数组的哪⼀个位置,然后再遍历⼀次,依次放到对应的位置即可。

public int[] reorderArray(int[] nums) {
if (nums == null || nums.length == 0) {
return nums;
} // 使用ArrayList动态存储,避免预先计算大小
List<Integer> oddList = new ArrayList<>();
List<Integer> evenList = new ArrayList<>(); // 第一次遍历:分离奇偶数
for (int num : nums) {
if (num % 2 != 0) {
oddList.add(num);
} else {
evenList.add(num);
}
} // 合并结果
int[] result = new int[nums.length];
int index = 0;
for (int odd : oddList) {
result[index++] = odd;
}
for (int even : evenList) {
result[index++] = even;
} return result;
}
  • 时间复杂度​:O(n),需要遍历数组两次(分离和合并各一次)
  • 空间复杂度​:O(n),需要额外的两个列表存储所有元素

双指针原地排序(类似插入排序)

使用类似插入排序的思想,维护一个"已排序奇数"的边界,当遇到奇数时,将其插入到边界位置并移动边界。这种方法不需要额外空间,但时间复杂度较高。

public int[] reorderArray(int[] nums) {
if (nums == null || nums.length == 0) {
return nums;
} int oddBoundary = 0; // 奇数边界
for (int i = 0; i < nums.length; i++) {
if (nums[i] % 2 != 0) {
// 从i位置向前移动到oddBoundary位置
int temp = nums[i];
// 将[i-1, oddBoundary]区间元素后移一位
for (int j = i - 1; j >= oddBoundary; j--) {
nums[j + 1] = nums[j];
}
nums[oddBoundary] = temp;
oddBoundary++;
}
} return nums;
}
  • 时间复杂度​:O(n²),最坏情况下每次奇数都需要移动大量元素
  • 空间复杂度​:O(1),原地排序,不需要额外空间

两次遍历填充法

通过两次遍历数组,第一次填充所有奇数,第二次填充所有偶数。这种方法结合了方法一的思路,但使用固定大小的结果数组

public int[] reorderArray(int[] nums) {
if (nums == null || nums.length == 0) {
return nums;
} int[] result = new int[nums.length];
int index = 0; // 第一次遍历:填充奇数
for (int num : nums) {
if (num % 2 != 0) {
result[index++] = num;
}
} // 第二次遍历:填充偶数
for (int num : nums) {
if (num % 2 == 0) {
result[index++] = num;
}
} return result;
}
  • 时间复杂度​:O(n),需要遍历数组两次
  • 空间复杂度​:O(n),需要一个结果数组

稳定的双指针交换法

使用两个指针,一个从前往后找偶数,一个从后往前找奇数,然后交换它们的位置。这种方法需要特别注意保持相对顺序

public int[] reorderArray(int[] nums) {
if (nums == null || nums.length == 0) {
return nums;
} int left = 0, right = nums.length - 1; while (left < right) {
// 从左找第一个偶数
while (left < right && nums[left] % 2 != 0) {
left++;
}
// 从右找第一个奇数
while (left < right && nums[right] % 2 == 0) {
right--;
} if (left < right) {
// 交换并保持相对顺序
int temp = nums[left];
// 将[left+1, right]区间元素前移一位
for (int i = left + 1; i <= right; i++) {
nums[i - 1] = nums[i];
}
nums[right] = temp;
}
} return nums;
}
  • 时间复杂度​:O(n²),最坏情况下需要移动大量元素
  • 空间复杂度​:O(1),原地操作

优化的双指针法(保持稳定性)

结合双指针和插入排序的思想,维护奇数指针和遍历指针,当遇到奇数时,将其插入到奇数指针位置并移动指针。

public int[] reorderArray(int[] nums) {
if (nums == null || nums.length == 0) {
return nums;
} int oddPos = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] % 2 != 0) {
// 记录当前奇数
int temp = nums[i];
// 将[oddPos, i-1]区间元素后移一位
for (int j = i; j > oddPos; j--) {
nums[j] = nums[j - 1];
}
nums[oddPos] = temp;
oddPos++;
}
} return nums;
}
  • 时间复杂度​:O(n²),最坏情况下需要移动大量元素
  • 空间复杂度​:O(1),原地操作

方法对比与总结

方法 时间复杂度 空间复杂度 优点 缺点
辅助数组法 O(n) O(n) 实现简单,顺序有保证 空间开销大
双指针原地排序 O(n²) O(1) 空间效率高 时间效率低
两次遍历填充法 O(n) O(n) 时间效率高 空间开销中等
稳定双指针交换法 O(n²) O(1) 空间效率高 实现复杂,时间效率低
优化双指针法 O(n²) O(1) 空间效率高,顺序保证好 时间效率低

剑指offer-13、调整数组顺序使奇数位于偶数前面(一)的更多相关文章

  1. 剑指Offer 13. 调整数组顺序使奇数位于偶数前面 (数组)

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

  2. [剑指Offer] 13.调整数组顺序使奇数位于偶数前面

    题目描述 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变. [思路1]用2n ...

  3. 剑指 Offer——13. 调整数组顺序使奇数位于偶数前面

    题目描述 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变.这和书本不太一样. 解 ...

  4. 剑指offer:调整数组顺序使奇数位于偶数前面

    题目 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分. 分析 事实上,这个题比较简单,很多种方式都可以实现,但是其时间复杂度或空间复 ...

  5. 剑指Offer:调整数组顺序使奇数位于偶数前面【21】

    剑指Offer:调整数组顺序使奇数位于偶数前面[21] 题目描述 输入一个整形数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分. 解题分析 使用插 ...

  6. 剑指 Offer 21. 调整数组顺序使奇数位于偶数前面

    剑指 Offer 21. 调整数组顺序使奇数位于偶数前面 Offer 21 这题的解法其实是考察快慢指针和头尾指针. package com.walegarrett.offer; /** * @Aut ...

  7. 【Java】 剑指offer(21) 调整数组顺序使奇数位于偶数前面

    本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇 ...

  8. 【剑指Offer】调整数组顺序使奇数位于偶数前面 解题报告(Python)

    [牛客网]调整数组顺序使奇数位于偶数前面 解题报告 标签(空格分隔): 牛客网 题目地址:https://www.nowcoder.com/questionTerminal/beb5aa231adc4 ...

  9. 剑指offer(07)-调整数组顺序使奇数位于偶数前面【转】

    来源:http://www.acmerblog.com/offer-6-2429/ 题目来自剑指offer系列 九度 1516 题目描述: 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得 ...

  10. Go语言实现:【剑指offer】调整数组顺序使奇数位于偶数前面

    该题目来源于牛客网<剑指offer>专题. 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和 ...

随机推荐

  1. MySQL——InnoDB存储引擎

    .ibd文件结构 从 MySQL 5.6.6 版本开始,默认一个表是一个.ibd文件,关于表的所有信息都保存在这个文件里.数据库IO操作的基本单位是页,.idb的基本组成也是页,如下图所示,一个.id ...

  2. java基础--抽象类、接口

    final(最终.修饰符) ## final关键字的用法: 1. final关键字修饰一个基本类型的变量时,该变量不能重新赋值,第一次的值为最终的. 2. fianl关键字修饰一个引用类型变量时,该变 ...

  3. Oracle中复杂数据处理

    利用聚合函数统计数据 求最大值-max() max()可应用数值型和字符型和日期型(实质也是数值型) select max(employee_age) max_age from employees m ...

  4. 前端开发系列111-工程化篇之Yeoman脚手架工具使用入门

    Yeoman是一款流行的前端的脚手架工具. 脚手架工具可以用来快速的自动生成项目的必要文件和基础文件结构.Yeoman使用的内建命令为yo,同时它自己也是一个包管理工具和自动化任务工具,它基于特定的模 ...

  5. docker安装和镜像管理

    centos版本8.5 清除密钥文件,开机会自动生成 rm -rf ssh_host_* 清除机械id cat /dev/bull > /etc/machine-id 关机 这样的话,模版就完成 ...

  6. Rust中struct的function与method

    一个示例就能看明白,关键处皆有注释,大致要点:impl 一个struct时,1.如果方法参数为&self,则为方法 ,可以用"对象实例.方法"来调用2.如果方法参数不是&a ...

  7. OpenList挂载「PikPak」

    存储->添加 选择PikPak 填写挂载路径 填写具体信息:用户名为自己 PikPak 的邮箱(登陆方式),密码为自己的密码. 获取刷新令牌 先在浏览器登录 PikPak 的 Web 端. 按 ...

  8. Django实战:Python代码规范指南

    一.PEP 8:Python 代码风格的基石 在团队协作和项目维护中,一致的代码风格至关重要.它不仅能提高代码的可读性,还能减少沟通成本,提升开发效率. PEP 8 是 Python 官方发布的代码风 ...

  9. GROOVY 异常处理 try catch

    try catch finally class Demo{ static void main(String[] args){ try{ File file = new File("./Exa ...

  10. 用 CloudQuery 管理和操作数据库,更高效更安全

    导语:用 CloudQuery 管理和操作数据,更高效更安全 工欲善其事,必先利其器,优秀的工具在数据管理和数据操作中有着极为重要的作用.市面上现已经有如 navicat.PL/SQL develop ...