剑指offer 题21—调整数组顺序是奇书位于偶数前面

2023-10-08 14:32

本文主要是介绍剑指offer 题21—调整数组顺序是奇书位于偶数前面,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

调整数组顺序是奇书位于偶数前面

题目

输入一个整数数组,实现一个函数来调整该数组中的数字的顺序,使得所有计数位于数组的前半部分,所有偶数位于数组的后半部分

初步分析

最简单的办法当然是从头扫描这个数组,每碰到一个偶数,就该数放到最后面,也就是这个数后面的数都要向前移动。
由于每碰到一个偶数就要移动O(n)个数字,总的时间复杂度为O(n^2)。

更好的办法

既然数组中只有两类数字——非奇即偶。那么每当发现有偶数出现在奇数前面时,就交换它们的顺序,这样岂不是可以了?

因此,需要维护两个指针:
第一个指针,初始化时指向第一个数字,只能向后移动。
第二个指针,初始化时指向最后一个数字,只能向前移动。

两指针相遇之前,如果第一个指针是偶数,而第二个指针是奇数,那么就将它们的位置交换

举例

输入数组:{1,2,3,4,5}

过程:
1、开始,第一个指针指向1,第二个指针指向5
2、由于1是奇数,因此第一个指针向后移动,直到指向偶数2。
3、此时,因为第二个指针指向5,因此交换,并且两者都进行移动。
4、然后继续直到两者相遇

图解:
在这里插入图片描述
因此可以得到以下代码:

void ReorderOddEven(int* pData,unsigned int length)
{if(pData==nullptr || length==0)return;int* pBegin=pData;int* pEnd=pData+length+1;while(pBegin<pEnd){//向后移动pBegin 直到它指向偶数while(pBegin<pEnd && (*pBegin & 0x1)!=0)pBegin++;//向前移动pEnd 直到指向奇数while(pBegin<pEnd && (*pEnd & 0x1)==0)pEnd--;if(pBegin<pEnd){int temp=*pBegin;*pBegin=*pEnd;*pEnd=tmp;}}
}

拓展——模块化的处理

上面的问题解决了,似乎也很完美,但是如果又有类似得问题如何?

问:如果改成数组分为正负两部分,负数在非负数前面,怎么处理?
答:重新定义一个新函数,只需要更改第二个和第三个while循环得判断条件就好了

再问:那如果又是分成两部分,一部分能被3整除,放前面,一部分不能被3整除,放后面,又怎么办呢?
再答:还是重新定义一个新函数,再更改… 打断:停停停,就没有更好得办法了?

我们看上面得问题,其实回答并没有错,因此就是只需要改一下条件就好了。
但上面错就错在这个只需要上面了

既然只是判断条件有需要改,那么我何必要每次都重复写其它一样的代码呢?
为何不将需要判断的条件封装起来,这样剩下的代码不就可以重用了?
没错,这正式提问者所想得到的答案!

因此我们只需要引入一个函数指针,将上面代码拆分成逻辑和运算两部分就好了。这样每次只需要重写逻辑函数,而不必重复一大段运算了,重用性提高了很多

void ReorderOddEven(int* pData,unsigned int length,bool (*func)(int))
{if(pData==nullptr || length==0)return;int* pBegin=pData;int* pEnd=pData+length+1;while(pBegin<pEnd){//向后移动pBegin 直到它指向偶数while(pBegin<pEnd && !func(*pBegin))pBegin++;//向前移动pEnd 直到指向奇数while(pBegin<pEnd && func(*pEnd) )pEnd--;if(pBegin<pEnd){int temp=*pBegin;*pBegin=*pEnd;*pEnd=tmp;}}
}bool IsEven(int n)
{return (n&0x1)==0;
}

————————————————————————————————————————————————————————
参考书籍:《剑指offer》

这篇关于剑指offer 题21—调整数组顺序是奇书位于偶数前面的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/165959

相关文章

C++初始化数组的几种常见方法(简单易懂)

《C++初始化数组的几种常见方法(简单易懂)》本文介绍了C++中数组的初始化方法,包括一维数组和二维数组的初始化,以及用new动态初始化数组,在C++11及以上版本中,还提供了使用std::array... 目录1、初始化一维数组1.1、使用列表初始化(推荐方式)1.2、初始化部分列表1.3、使用std::

C++ Primer 多维数组的使用

《C++Primer多维数组的使用》本文主要介绍了多维数组在C++语言中的定义、初始化、下标引用以及使用范围for语句处理多维数组的方法,具有一定的参考价值,感兴趣的可以了解一下... 目录多维数组多维数组的初始化多维数组的下标引用使用范围for语句处理多维数组指针和多维数组多维数组严格来说,C++语言没

Python中顺序结构和循环结构示例代码

《Python中顺序结构和循环结构示例代码》:本文主要介绍Python中的条件语句和循环语句,条件语句用于根据条件执行不同的代码块,循环语句用于重复执行一段代码,文章还详细说明了range函数的使... 目录一、条件语句(1)条件语句的定义(2)条件语句的语法(a)单分支 if(b)双分支 if-else(

关于Spring @Bean 相同加载顺序不同结果不同的问题记录

《关于Spring@Bean相同加载顺序不同结果不同的问题记录》本文主要探讨了在Spring5.1.3.RELEASE版本下,当有两个全注解类定义相同类型的Bean时,由于加载顺序不同,最终生成的... 目录问题说明测试输出1测试输出2@Bean注解的BeanDefiChina编程nition加入时机总结问题说明

C++实现封装的顺序表的操作与实践

《C++实现封装的顺序表的操作与实践》在程序设计中,顺序表是一种常见的线性数据结构,通常用于存储具有固定顺序的元素,与链表不同,顺序表中的元素是连续存储的,因此访问速度较快,但插入和删除操作的效率可能... 目录一、顺序表的基本概念二、顺序表类的设计1. 顺序表类的成员变量2. 构造函数和析构函数三、顺序表

Java 字符数组转字符串的常用方法

《Java字符数组转字符串的常用方法》文章总结了在Java中将字符数组转换为字符串的几种常用方法,包括使用String构造函数、String.valueOf()方法、StringBuilder以及A... 目录1. 使用String构造函数1.1 基本转换方法1.2 注意事项2. 使用String.valu

JAVA中整型数组、字符串数组、整型数和字符串 的创建与转换的方法

《JAVA中整型数组、字符串数组、整型数和字符串的创建与转换的方法》本文介绍了Java中字符串、字符数组和整型数组的创建方法,以及它们之间的转换方法,还详细讲解了字符串中的一些常用方法,如index... 目录一、字符串、字符数组和整型数组的创建1、字符串的创建方法1.1 通过引用字符数组来创建字符串1.2

JAVA利用顺序表实现“杨辉三角”的思路及代码示例

《JAVA利用顺序表实现“杨辉三角”的思路及代码示例》杨辉三角形是中国古代数学的杰出研究成果之一,是我国北宋数学家贾宪于1050年首先发现并使用的,:本文主要介绍JAVA利用顺序表实现杨辉三角的思... 目录一:“杨辉三角”题目链接二:题解代码:三:题解思路:总结一:“杨辉三角”题目链接题目链接:点击这里

vue如何监听对象或者数组某个属性的变化详解

《vue如何监听对象或者数组某个属性的变化详解》这篇文章主要给大家介绍了关于vue如何监听对象或者数组某个属性的变化,在Vue.js中可以通过watch监听属性变化并动态修改其他属性的值,watch通... 目录前言用watch监听深度监听使用计算属性watch和计算属性的区别在vue 3中使用watchE

hdu2241(二分+合并数组)

题意:判断是否存在a+b+c = x,a,b,c分别属于集合A,B,C 如果用暴力会超时,所以这里用到了数组合并,将b,c数组合并成d,d数组存的是b,c数组元素的和,然后对d数组进行二分就可以了 代码如下(附注释): #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<que