如有需要请认真看完 ~ 结尾有惊喜彩蛋哦

  1. KVO实现原理 当观察某对象时,runtime机制会动态为该对象添加一个子类,并为子类重写被观察属性的setter方法,由setter方法通知被观察属性的改变状态。触发KVO的主要是调用willChangeValueForKey和didChangeValueForKey。

  2. 类和结构体的区别 类是引用类型,结构体是值类型。结构体变量分配在栈,OC对象分配在堆。结构体只能封装属性,类不仅可以封装属性也可以封装方法。

  3. 堆和栈的区别 栈是由编译器自动分配释放,存储局部和临时变量,栈的存储空间是连续的;堆是由程序员自己分配释放的,堆的存储空间是不连续的;栈对象分配内存速度快,在栈中不会发生内存泄漏,堆对象可以自己掌控生命周期,但是容易造成内存泄漏。

  4. 开发中遇到的内存泄漏 使用AFN时候需要用到SessionManager,如果多次创建SessionManager就会造成内存泄漏,此时需要我们创建SessionManager单例进行全局管理;循环引用导致的内存泄漏,block的循环引用,delegate的循环引用,NSTimer的循环引用。

  5. property修饰符 1、原子性 atomic,对属性读写操作时候会加锁会造成性能损耗,但不等于线程安全;nonatomic,对属性读写时候不会加锁,提高读写效率; 2、读写权限 readwrite,可读可写,既有setter方法又有getter方法,readonly,只读,只有getter方法; 3、内存管理 strong,指向并拥有该对象,修饰的对象引用计数会加1;weak,指向但不拥有该对象,修饰的对象引用计数不会加1,代理用weak修饰避免循环引用;copy,与strong类似,不同的是strong的复制是多个指针指向同一个地址,copy的复制是在内存中复制一份对象,指针指向不同地址,一般用在修饰有对应可变类型的不可变对象上,block用copy修饰;assign,直接赋值,用于基本数据类型。

  6. weak和assign的区别 weak一般用于修饰对象类型,assign一般用于修饰基本数据类型,assign修饰的对象被释放后,指针的地址依然存在,会造成野指针,而weak修饰的对象被释放后,指针会自动被置为nil。

  7. block为什么要用copy修饰 block创建时候默认分配在栈区,作用域仅限创建时候的当前上下文,可能随时被收回,为了能在作用域外调用block,在操作的时候不被收回,需要将block从栈区复制到堆区。

  8. block的实现原理 block是C语言的扩充,是一个自动包含局部变量的匿名函数。block其实就是一个OC对象,而这个OC对象又是一个结构体,在结构体中他有6个属性,ISA指针,指向对象的类;flags,按bit位表示block的附加信息;reserved,保留变量;invoke函数指针,指向具体block实现的函数调用地址;descriptor,表示block的附加信息;variables,block捕获到的变量参数,block就是通过这些参数访问外部变量的。

  9. 什么时候用weak 1、代理用weak修饰,避免循环引用,并且不会造成野指针错误; 2、storyboard或xib拖拽生成的属性用weak修饰,用storyboard或xib创建的控件视图已经对其有着引用关系。

  10. weak修饰的对象释放后为什么会被置为nil(weak实现原理) weak其实是runtime维护的一张哈希表,用于存储指向某个对象的所有weak指针。其中key是所指对象的地址,value是weak指针的地址数组。初始化时候,runtime调用objc_initWeak()函数,初始化一个新的weak指针指向对象的地址,引用时候,objc_initWeak()调用objc_storeWeak()函数,更新指针指向,并创建对应弱引用表,释放时,调用clearDeallocating()函数,根据对象地址获取weak指针的数组,遍历数组将其中的元素置为nil,最后从weak表中删除,清除对象的记录。

  11. block和delegate的区别 block的运行成本高,出栈操作需要将使用的数据从栈内存拷贝到堆内存,delegate的运行成本低,只保存一个对象指针直接回调;block可以很方便的修改上下文变量,delegate只能通过参数传递方式修改;block代码集中,可读性高,delegate代码分散,并且需要声明和实现;delegate用weak修饰就能避免循环引用,block稍不注意就会导致循环引用。

  12. 对runtime的理解 OC是运行时语言,对象类型的确定由编译时推迟到运行时,在runtime中对象用结构体表示,ISA指针,实例对象指向类,类对象指向元类;super_class,指向父类;ivars,存储成员变量;methodLists,存储方法;protocols,存储协议方法;instance_size,确定对象长度;cache,对象缓存。通过这些属性,我们可以获取对象的成员变量列表、属性列表、方法列表、协议列表等;可以交换方法,动态添加方法;可以动态添加类,为类添加实例变量,为分类添加属性。

  13. runtime的消息发送机制 当我们向对象发送消息时,编译器在运行时会转化为objc_msgSend()函数,转化时候除了方法本身的参数以外,还隐藏又两个参数,一个是id类型表示对象类型,一个是SEL类型,是函数对应的编号。对象通过ISA找到其对应的类,通过SEL去对应的类的方法列表中找,如果未找到就去父类中找,一直找到NSObject类。如果仍未找到,此时runtime会给我们三次机会保证程序不崩溃,第一次,动态方法解析,通过resolveClassMethod()函数或resolveInstanceMethod()函数提供一次添加方法的机会,如果添加一个函数并返回YES,就会执行这个函数,否则就等待重定向,通过forwardingTargetForSelector函数返回一个实现该方法的对象,如果返回self或NO,就消息转发,通过methodSignatureForSelector()函数,将方法参数返回值打包成一个NSInvocation对象,通过forwardInvacation()函数将这个Invocation对象发送给提供一个方法实现的对象。

  14. ISA是什么 ISA是一个Class类型的指针,每个实例对象都有一个ISA指针,指向对象的类,每个Class也有一个ISA指针,指向元类,元类也是有一个ISA指针,最终指向根类,而根类的ISA指针指向自己,最终形成一个封闭的内循环。

  15. load和initialize的区别 load:类被应用时执行,每个类的load方法只调用一次,当父类和子类都实现了load方法,父类先调用,子类后调用,当子类未实现oad方法,父类的load方法仍会调用;类中的load方法优先于分类中的load方法,分类的load方法调用顺序和导入工程的顺序一致,即compile source中的顺序。 initialize:类的第一个方法被调用前执行,由系统自动调用。无论子类是否实现initialize方法,都会执行父类的initialize方法,当子类实现initialize方法时,子类执行子类的initialize方法方法;当子类未实现initialize方法时,子类执行父类的initialize方法;分类的initialize方法会覆盖主类的initialize方法。

  16. GCD和NSOperation的区别 GCD是基于C语言实现的,能够利用多核CPU的优势处理多线程充分发挥CPU的使用;NSOperation基于cocoa框架实现的,更加面向对象,可以监听线程的执行状态,可以很容易管理线程间的依赖关系,能够设置最大并发数。

  17. GCD资源竞争和死锁 导致资源竞争的原因是,两个线程争夺同一资源。因此解决资源竞争的方法就是线程在拥有资源的时候对资源加锁,另一线程只有等待解锁以后才可以拥有该资源。 两个线程相互等待对方释放资源就会导致死锁,最常见的死锁是使用dispatch_sync。解决死锁的办法:异步执行。

  18. iOS常见的锁 同步锁;信号量;互斥锁;对象锁;条件锁;自旋锁;读写锁;递归锁

  19. 对ARC内存管理的理解 OC的内存管理就是对引用计数的管理,ARC就是自动引用计数,在我们编译时候编译器会分析源码中每个对象的生命周期,基于这些周期添加对应的引用计数。

  20. 自动释放池的实现原理 每个线程都有一个runloop,并且维护着自己的自动释放池,由于子线程的runloop默认是不开启的,也就意味着子线程不会自动创建自动释放池。自动释放池以栈的形式实现,当runloop开始一次循环时候就会创建自动释放池,它将被添加到栈顶,调用了对象的autorelease方法,这个对象就会被存储到栈顶的自动释放池中,当自动释放池满或者一次runloop循环结束时候就会向自动释放池中的对象发release消息,自动释放池被回收。

  21. 自动释放池在runloop中如何工作的 APP启动,在主线程runloop中注册了两个observe,第一个observe监听即将进入runloop,在其回调内调用objc_autoreleasePoolPush()创建自动释放池,优先级最高,保证创建自动释放池在其他操作之前;第二个observe监听两个事件:即将进入睡眠,调用objc_autoreleasePoolPop()和objc_autoreleasePoolPush()释放旧池并创建新池;即将退出runloop时调用objc_autoreleasePoolPop()释放自动释放池,其observe优先级最低,保证释放池释放在其他所有回调之后。

  22. 对runloop的理解 runloop是一个对象,这个对象在循环中处理程序运行中出现的各种事件,触摸事件、UI刷新事件、定时器事件、方法事件等,从而保持程序的持续运行,在没有事件处理时候进入睡眠模式,从而节省CPU资源,提高程序性能。 每个线程都有对应的唯一一个runloop,主线程的runloop在程序启动时候就自动创建,其他线程的runloop都需要手动启动。runloop并不是线程安全的,因此要避免在其他线程调用当前线程的runloop。

  23. runloop的mode和源 mode: NSDefaultRunLoopMode,默认 UITrackingRunLoopMode,scrollView滑动时 UIInitializationRunLoopMode,程序启动时 NSEventTrackingRunLoopMode,界面跟踪触摸事件时 NSRunLoopCommonModes,mode集 源: 定时器源和输入源,其中输入源有source0和source1,source0自定义输入源,source1基于端口的输入源。

  24. 如何创建一个常驻线程 创建一个线程,在线程中开启runloop,添加match_port的输入源,调用run方法启动runloop。

  25. tableView如何优化 1、cell复用 2、复杂业务处理放在子线程 3、视图尽量避免使用透明颜色,尽量减少使用CALayer 4、cell高度缓存 5、数据预加载 6、自定义cell,视图使用懒加载,尽量减少addSubView给cell动态添加View 7、耗时的UI操作可以通过CFRunLoopRef对象处理

  26. cell复用机制 tableView有一个visibleCells数组保存显示的cell和reusableTableCells字典保存可复用的cells以及对应的id,显示第一屏cell时候,reusableTableCells为空,dequeueReusableCell获取cell时候返回nil,通过初始化方法创建cell,当第一个cell完全移除屏幕时候,这时候需要再显示一个cell,从reusableTableCells中取到为空,再初始化一个添加到visibleCells中,同时第一个cell就从visibleCells中移除,添加到reusableTableCells中,之后再有cell移除屏幕时reusableTableCells就有值,就可以正常复用。 cell复用会调用哪个方法?prepareForReuse

  27. NSCache和NSDictionary的区别 NSCache是线程安全的,在多线程操作时不需要加锁,NSCache在系统发出低内存通知时能够自动删除缓存,NSCache只是对对象的抢引用,对象不需要实现NSCoding协议。

  28. NSString、NSArrary、NSDictionary用什么修饰 NSString用copy修饰,NSArray和 NSDictionary根据实际需求,如果有可变数组或可变字典赋值给NSSArray或NSDictionary用copy修饰,可变对象的copy是深复制,即把整个对象内存都复制到另外一块内存中,这样对原对象做任何操作都不会影响新对象的内容。

  29. 对HTTP、TCP、UDP的理解 TCP/IP是一个协议组,分为三个层次:应用层、传输层、网络层,在应用层有 HTTP协议,在传输层有TCP、UDP协议,在网络层有IP协议。 HTTP是应用层的超文本传输协议,HTTP协议是建立在请求/响应模型上的,首先由客户端建立一条与服务器的TCP链接,并发送请求,请求中包含请求方法、URI、协议版本以及相关的MIME样式消息,服务端响应状态,返回协议版本、成功失败码以及相关的MIME样式消息。 TCP和UDP都是基于传输层的协议,TCP是基于连接的协议,需要经过三次握手建立连接,因此传输速度慢,而UDP是面向非连接的协议,因此会出现丢包的情况。

  30. TCP的三次握手 第一次握手:客户端向服务器发起连接请求时,向服务器发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认; 第二次握手:服务器收到syn包,确认客户端的SYN(ack=j+1),同时自己也发一个SYN包(syn=k),即SYN+ACK,服务器进入SYN_RECV状态; 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包(ack=k+1),客户端和服务器TCP连接成功。

  31. ISO的七层模型 应用层、表示层、会话层、传输层、网络层、数据链路层、物理层

  32. websocket和Socket的区别 websocket是建立在TCP之上的应用层协议,和HTTP不同的是它是双向通信协议。Socket其实是为了方便使用TCP或UDP抽象出来的位于传输层和应用层之间的一组接口。

  33. APP启动时间优化 首先要知道APP启动的过程,APP启动会加载资源文件,动态库,初始化runtime,执行类的load方法,applicationdidfinish方法加载window和第一个VC,最终显示第一个画面。优化启动时间就尽量减少导入资源文件,删除无用的资源文件和动态库,减少使用storyboard和xib,减少在applicationdidfinish中的耗时操作。

  34. MVC的优缺点 优点:代码总量少,简单易懂 缺点:代码过于集中,难以进行测试,难以扩展,网络请求逻辑无处安放

  35. Category的实现原理,Category为什么不能添加实例变量 分类的实现原理是将category中的方法,属性,协议数据放在category_t结构体中,然后将结构体内的方法列表拷贝到类对象的方法列表中。 Category可以添加属性,但是并不会自动生成成员变量及set/get方法。因为category_t结构体中并不存在成员变量。对象的成员变量是存放在实例对象中的,并且编译的那一刻就已经决定好了。而分类是在运行时才去加载的。那么我们就无法在程序运行时将分类的成员变量中添加到实例对象的结构体中。因此分类中不可以添加成员变量。

  36. Category中有load方法吗?load方法是什么时候调用的?load 方法能继承吗? Category中有load方法,load方法在程序启动装载类信息的时候就会调用。load方法可以继承。调用子类的load方法之前,会先调用父类的load方

37.事件传递流程 发生一个触摸事件后,系统会把这个事件放在UIApplication管理的事件队列中,UIApplication充事件队列中取到第一个事件,将事件分发给window,window寻找处理事件最合适的View,调用View的touchs方法处理具体事件。

  1. 应用如何找到最合适的控件来处理事件 1.首先判断主窗口(keyWindow)自己是否能接受触摸事件 2.判断触摸点是否在自己身上 3.子控件数组中从后往前遍历子控件,重复前面的两个步骤(所谓从后往前遍历子控件,就是首先查找子控件数组中最后一个元素,然后执行1、2步骤) 4.view,比如叫做fitView,那么会把这个事件交给这个fitView,再遍历这个fitView的子控件,直至没有更合适的view为止。 5.如果没有符合条件的子控件,那么就认为自己最合适处理这个事件,也就是自己是最合适的view。

  2. UIView什么情况下不能接收触摸事件 不允许交互:userInteractionEnabled = NO 隐藏:如果把父控件隐藏,那么子控件也会隐藏,隐藏的控件不能接受事件 透明度:如果设置一个控件的透明度<0.01,会直接影响子控件的透明度。alpha:0.0~0.01为透明。 默认UIImageView不能接受触摸事件,因为不允许交互,即userInteractionEnabled = NO。所以如果希望UIImageView可以交互,需要设置UIImageView的userInteractionEnabled = YES。

  3. 如何绘制UIView? 绘制一个UIView最灵活的方法就是由它自己完成绘制。实际上你不是绘制一个UIView,而是子类化一个UIView并赋予绘制自己的能力。当一个UIView需要执行绘制操作时,drawRect:方法就会被调用,覆盖此方法让你获得绘图操作的机会。当drawRect:方法被调用,当前图形的上下文也被设置为属于视图的图形上下文,你可以使用Core Graphic或者UIKit提供的方法将图形画在该上下文中。

  4. 什么是MVVM?主要目的是什么?优点有哪些? MVVM即 Model-View-ViewModel 1.View主要用于界面呈现,与用户输入设备进行交互、 2.ViewModel是MVVM架构中最重要的部分,ViewModel中包含属性,方法,事件,属性验证等逻辑,负责View与Model之间的通讯 3.Model就是我们常说的数据模型,用于数据的构造,数据的驱动,主要提供基础实体的属性。 MVVM主要目的是分离视图和模型 MVVM优点:低耦合,可重用性,独立开发,可测试

  5. get请求与post请求的区别 1.get是向服务器发索取数据的一种请求,而post是向服务器提交数据的一种请求 2.get没有请求体,post有请求体 3.get请求的数据会暴露在地址栏中,而post请求不会,所以post请求的安全性比get请求号 4.get请求对url长度有限制,而post请求对url长度理论上是不会收限制的,但是实际上各个服务器会规定对post提交数据大小进行限制。

  6. 谈谈你对多线程开发的理解?ios中有几种实现多线程的方法? 好处:

  • 使用多线程可以把程序中占据时间长的任务放到后台去处理,如图片,视频的下载;
  • 发挥多核处理器的优势,并发执行让系统运行的更快,更流畅,用户体验更好; 缺点:
  • 大量的线程降低代码的可读性;
  • 更多的线程需要更多的内存空间;
  • 当多个线程对同一个资源出现争夺的时候要注意线程安全的问题。 ios有3种多线程编程的技术:1.NSThread,2.NSOperationQueue,3.gcd;
  1. XMPP工作原理;xmpp系统特点 原理:
  • 所有从一个client到另一个client的jabber消息和数据都要通过xmpp server
  • client链接到server
  • server利用本地目录系统的证书对其认证
  • server查找,连接并进行相互认证
  • client间进行交互 特点:
  • 客户机/服务器通信模式;
  • 分布式网络;
  • 简单的客户端;
  • XML的数据格式
  1. 地图的定位是怎么实现的? 1.导入了CoreLocation.framework 2.ios8以后,如果需要使用定位功能,就需要请求用户授权,在首次运行时会弹框提示 3.通过本机自带的gps获取位置信息(即经纬度)

  2. 苹果内购实现流程 程序通过bundle存储的plist文件得到产品标识符的列表。程序向App Store发送请求,得到产品的信息。App Store返回产品信息。程序把返回的产品信息显示给用户(App的store界面)用户选择某个产品程序向App Store发送支付请求App Store处理支付请求并返回交易完成信息App获取信息并提供内容给用户。

  3. 支付宝,微信等相关类型的sdk的集成 1.在支付宝开发平台创建应用并获取APPID 2.配置密钥 3.集成并配置SDK 4.调用接口(如交易查询接口,交易退款接口)

  4. gcd产生死锁的原因及解锁的方法 产生死锁的必要条件:1.互斥条件,2.请求与保持条件,3.不剥夺条件,4.循环等待条件。 解决办法:采用异步执行block。

  5. 生成二维码的步骤 1.使用CIFilter滤镜类生成二维码 2.对生成的二维码进行加工,使其更清晰 3.自定义二维码背景色、填充色 4.自定义定位角标 5.在二维码中心插入小图片

  6. 在使用XMPP的时候有没有什么困难 发送附件(图片,语音,文档...)时比较麻烦XMPP框架没有提供发送附件的功能,需要自己实现 实现方法,把文件上传到文件服务器,上传成功后获取文件保存路径,再把附件的路径发送给好友

  7. 是否使用过环信,简单的说下环信的实现原理 环信是一个即时通讯的服务提供商 环信使用的是XMPP协议,它是再XMPP的基础上进行二次开发,对服务器Openfire和客户端进行功能模型的添加和客户端SDK的封装,环信的本质还是使用XMPP,基于Socket的网络通信 环信内部实现了数据缓存,会把聊天记录添加到数据库,把附件(如音频文件,图片文件)下载到本地,使程序员更多时间是花到用户体验体验上。

没看过瘾 搜素QQ群 776598941 加入iOS社区群 收获更多精选面试题或者点击此处直接进群

算法

一、对以下一组数据进行降序排序(冒泡排序)。“24,17,85,13,9,54,76,45,5,63”

int main(int argc, char *argv[]) {int array[10] = {24, 17, 85, 13, 9, 54, 76, 45, 5, 63};int num = sizeof(array)/sizeof(int);for(int i = 0; i < num-1; i++) {for(int j = 0; j < num - 1 - i; j++) {if(array[j] < array[j+1]) {int tmp = array[j];array[j] = array[j+1];array[j+1] = tmp;}}}for(int i = 0; i < num; i++) {printf("%d", array[i]);if(i == num-1) {printf("\n");}else {printf(" ");}}}
复制代码

二、对以下一组数据进行升序排序(选择排序)。“86, 37, 56, 29, 92, 73, 15, 63, 30, 8”

void sort(int a[],int n)
{int i, j, index;for(i = 0; i < n - 1; i++) {index = i;for(j = i + 1; j < n; j++) {if(a[index] > a[j]) {index = j;}}if(index != i) {int temp = a[i];a[i] = a[index];a[index] = temp;}}}int main(int argc, const char * argv[]) {int numArr[10] = {86, 37, 56, 29, 92, 73, 15, 63, 30, 8};sort(numArr, 10);for (int i = 0; i < 10; i++) {printf("%d, ", numArr[i]);}printf("\n");return 0;}
复制代码

三、 快速排序算法

void sort(int *a, int left, int right) {if(left >= right) {return ;}int i = left;int j = right;int key = a[left];while (i < j) {while (i < j && key >= a[j]) {j--;}a[i] = a[j];while (i < j && key <= a[i]) {i++;}a[j] = a[i];}a[i] = key;sort(a, left, i-1);sort(a, i+1, right);}
复制代码

四、归并排序

void merge(int sourceArr[], int tempArr[], int startIndex, int midIndex, int endIndex) {int i = startIndex;int j = midIndex + 1;int k = startIndex;while (i != midIndex + 1 && j != endIndex + 1) {if (sourceArr[i] >= sourceArr[j]) {tempArr[k++] = sourceArr[j++];} else {tempArr[k++] = sourceArr[i++];}}while (i != midIndex + 1) {tempArr[k++] = sourceArr[i++];}while (j != endIndex + 1) {tempArr[k++] = sourceArr[j++];}for (i = startIndex; i <= endIndex; i++) {sourceArr[i] = tempArr[i];}}void sort(int souceArr[], int tempArr[], int startIndex, int endIndex) {int midIndex;if (startIndex < endIndex) {midIndex = (startIndex + endIndex) / 2;sort(souceArr, tempArr, startIndex, midIndex);sort(souceArr, tempArr, midIndex + 1, endIndex);merge(souceArr, tempArr, startIndex, midIndex, endIndex);}}int main(int argc, const char * argv[]) {int numArr[10] = {86, 37, 56, 29, 92, 73, 15, 63, 30, 8};int tempArr[10];sort(numArr, tempArr, 0, 9);for (int i = 0; i < 10; i++) {printf("%d, ", numArr[i]);}printf("\n");return 0;}
复制代码

五、 实现二分查找算法(编程语言不限)

int bsearchWithoutRecursion(int array[],int low,int high,int target) {while(low <= high) {int mid = (low + high) / 2;if(array[mid] > target)high = mid - 1;else if(array[mid] < target)low = mid + 1;else  //findthetargetreturn mid;}//the array does not contain the targetreturn -1;}
复制代码

递归实现

int binary_search(const int arr[],int low,int high,int key)
{int mid=low + (high - low) / 2;if(low > high)return -1;else{if(arr[mid] == key)return mid;else if(arr[mid] > key)return binary_search(arr, low, mid-1, key);elsereturn binary_search(arr, mid+1, high, key);}}六、如何实现链表翻转(链表逆序)? 思路:每次把第二个元素提到最前面来。#include <stdio.h>#include <stdlib.h>typedef struct NODE {struct NODE *next;int num;}node;node *createLinkList(int length) {if (length <= 0) {return NULL;}node *head,*p,*q;int number = 1;head = (node *)malloc(sizeof(node));head->num = 1;head->next = head;p = q = head;while (++number <= length) {p = (node *)malloc(sizeof(node));p->num = number;p->next = NULL;q->next = p;q = p;}return head;
}void printLinkList(node *head) {if (head == NULL) {return;}node *p = head;while (p) {printf("%d ", p->num);p = p -> next;}printf("\n");}node *reverseFunc1(node *head) {if (head == NULL) {return head;}node *p,*q;p = head;q = NULL;while (p) {node *pNext = p -> next;p -> next = q;q = p;p = pNext;}return q;}int main(int argc, const char * argv[]) {node *head = createLinkList(7);if (head) {printLinkList(head);node *reHead = reverseFunc1(head);printLinkList(reHead);free(reHead);}free(head);return 0;}
复制代码

七、 实现一个字符串“how are you”的逆序输出(编程语言不限)。如给定字符串为“hello world”,输出结果应当为“world hello”。

int spliterFunc(char *p) {char c[100][100];int i = 0;int j = 0;while (*p != '\0') {if (*p == ' ') {i++;j = 0;} else {c[i][j] = *p;j++;}p++;}for (int k = i; k >= 0; k--) {printf("%s", c[k]);if (k > 0) {printf(" ");} else {printf("\n");}}return 0;}
复制代码

八、 给定一个字符串,输出本字符串中只出现一次并且最靠前的那个字符的位置?如“abaccddeeef”,字符是b,输出应该是2。

char *strOutPut(char *);int compareDifferentChar(char, char *);int main(int argc, const char * argv[]) {char *inputStr = "abaccddeeef";char *outputStr = strOutPut(inputStr);printf("%c \n", *outputStr);return 0;}char *strOutPut(char *s) {char str[100];char *p = s;int index = 0;while (*s != '\0') {if (compareDifferentChar(*s, p) == 1) {str[index] = *s;index++;}s++;}return &str;
}int compareDifferentChar(char c, char *s) {int i = 0;while (*s != '\0' && i<= 1) {if (*s == c) {i++;}s++;}if (i == 1) {return 1;} else {return 0;}}
复制代码

九、二叉树的先序遍历为FBACDEGH,中序遍历为:ABDCEFGH,请写出这个二叉树的后序遍历结果。

ADECBHGF

先序+中序遍历还原二叉树:先序遍历是:ABDEGCFH 中序遍历是:DBGEACHF

首先从先序得到第一个为A,就是二叉树的根,回到中序,可以将其分为三部分:

左子树的中序序列DBGE,根A,右子树的中序序列CHF

接着将左子树的序列回到先序可以得到B为根,这样回到左子树的中序再次将左子树分割为三部分:

左子树的左子树D,左子树的根B,左子树的右子树GE

同样地,可以得到右子树的根为C

类似地将右子树分割为根C,右子树的右子树HF,注意其左子树为空

如果只有一个就是叶子不用再进行了,刚才的GE和HF再次这样运作,就可以将二叉树还原了。

十、 打印2-100之间的素数。

int main(int argc, const char * argv[]) {for (int i = 2; i < 100; i++) {int r = isPrime(i);if (r == 1) {printf("%ld ", i);}}return 0;}int isPrime(int n)
{int i, s;for(i = 2; i <= sqrt(n); i++)if(n % i == 0) return 0;return 1;}十一、 求两个整数的最大公约数。int gcd(int a, int b) {int temp = 0;if (a < b) {temp = a;a = b;b = temp;}while (b != 0) {temp = a % b;a = b;b = temp;}return a;}
复制代码

总结

以上就是为大家整理的在IOS面试中可能会遇到的常见算法问题和答案,希望这篇文章对大家的面试能有一定的帮助,如果有疑问大家可以加群 776598941探讨或者留言交流。

2019阿里巴巴技术面试题集锦!

链接:pan.baidu.com/s/1LX_a_xQj…

提取码:xikv

转载于:https://juejin.im/post/5d5404496fb9a06b155db6b7

五十一道19年精选面试题+十一道常问算法=提高面试成功率相关推荐

  1. 企业面试题|最常问的MySQL面试题集合(二)

    MySQL的关联查询语句 六种关联查询 交叉连接(CROSS JOIN) 内连接(INNER JOIN) 外连接(LEFT JOIN/RIGHT JOIN) 联合查询(UNION与UNION ALL) ...

  2. 企业面试题|最常问的MySQL面试题集合(一)

    问题1:char.varchar的区别是什么? varchar是变长而char的长度是固定的.如果你的内容是固定大小的,你会得到更好的性能. 问题2: TRUNCATE和DELETE的区别是什么? D ...

  3. MySQL 高频面试题,最常问!

    点击上方关注 "终端研发部" 设为"星标",和你一起掌握更多数据库知识作者:呼延十 原文链接:http://r6d.cn/uHd 前言 本文主要受众为开发人员, ...

  4. 第十五届全国青少年信息学奥林匹克联赛初赛试题

    第十五届全国青少年信息学奥林匹克联赛初赛试题(2009年),我只摘录了选择题,部分题目做了注解. 一.单项选择题 1.关于图灵机下面的说法哪个是正确的: A.图灵机是世界上最早的电子计算机. B.由于 ...

  5. 【金九银十】终一搏,BAT、TMD名企精选面试题93道(附解析)

    心态 心态很重要! 心态很重要! 心态很重要! 重要的事情说三遍,这一点我觉得是必须放到前面来讲. 找工作之前,有一点你必须清楚,就是找工作是一件看缘分的事情,不是你很牛,你就一定能进你想进的公司,都 ...

  6. 经济学说史-试题(十套)附答案

    经济学说史试题一 一.单项选择题 1.西斯蒙第认为资本主义发生经济危机的原因主要在于(   ) A.消费不足      B.有效需求不足        C.生产过剩         D.储蓄过多 2. ...

  7. 2018年3月计算机二级考试题,2018年3月计算机二级考试Access综合试题十

    2018年3月计算机等级考试即将开始,小编在这里为考生们整理了2018年3月计算机二级考试Access综合试题,希望能帮到大家,想了解更多资讯,请关注出国留学网的及时更新哦. 2018年3月计算机二级 ...

  8. JAVA基础精选面试题(持续更新,一天五道,祝各位道友,早日飞升上仙)!

    1.重载和重写的区别? 重载发生在一个类中,同名的方法如果有不同的参数列表(类型不同.个数 不同.顺序不同)则视为重载. 重写发生在子类与父类之间,重写要求子类重写之后的方法与父类被重写方 法有相同的 ...

  9. 五年级计算机课主要学哪些内容,五年级信息技术教学计划(精选4篇)

    五年级信息技术教学计划(精选4篇) 时间是箭,去来迅疾,又迎来了一个全新的起点,请一起努力,写一份教学计划吧.但是教学计划要写什么内容才能让人眼前一亮呢?下面是小编帮大家整理的五年级信息技术教学计划( ...

最新文章

  1. 南理工c语言程序设计,北理工年C语言程序设计考试.doc
  2. NPM:nodejs官方包管理工具的简介、安装、使用方法之详细攻略
  3. Redmine 数据库连接错误
  4. c语言static的用法_一文轻松掌握,单片机中C语言的数据存储与程序编写
  5. Java图形组件 OpenSwing
  6. Windows Builder 使用总结
  7. 基于JavaScript+css的购物网站项目
  8. linux网桥配置brctl
  9. Easy Iot实现MQTT实验
  10. numpy 求矩阵非零元素的均值
  11. 植物大战僵尸无限阳光(包括阳光基址的寻找)
  12. android拷机工具,Android 3DMark大更新:无敌拷机神器
  13. 年终敬酒万能语句(领导篇)
  14. 高斯消去法解线性方程组C++实现
  15. 电脑维护入门 GHOST 使用方法 图解说明
  16. 关于spoolsv.exe 报错,并打印服务停止的问题
  17. 6000字总结MySQL最基础的增删查改命令
  18. 阿里云ecs安全组管理(双可变宽带公网出口)
  19. 码云,git使用 教程
  20. 企业如何打造团队凝聚力培训PPT课件?

热门文章

  1. App开发者如何选择移动广告平台3 - 广告平台的选择标准
  2. 关于iView UI的表单Form如何进行前端验证
  3. 计算机考试考不好 检讨,考试成绩差检讨书5篇
  4. 【Azkaban】Azkaban入门解析
  5. Kotlin 与 Java 8 的重要新特性以及 Java 9、10 的发展规划
  6. redis有序集合sorted set(zset)数据类型相关命令介绍及使用
  7. 60道硬核 Python 面试题,论面霸是如何炼成的
  8. AES加密算法(Rijndael算法)
  9. Swoole中的进程和线程
  10. 修改网卡mac地址的思考