第一家试水,明显没状态。。

笔试题

数组求中间值下标

描述

已知一个数组,求得第一个下标,使得左边累加的和 跟 右边累加的和相同,要求时间复杂度为 O(n)。
例:
输入 a = [10,20,5,65,20,15] 输出为 3

解题思路

这道题最先想到的是嵌套循环,每次都求出下标左方的和,跟右方的和做对比,但是这样的时间复杂度是 O(n^2) 。
有个思路是这样: 先求出总和 sum ,接着遍历,并且记录当前坐标左侧元素和 leftSum ,假如 leftSum * 2 = sum - [当前下标值] ,那么肯定右边的元素值相加和 rightSum,即与 leftSum 值相同。OC 的实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

NSInteger sum = 0;
NSInteger index = -1;
NSArray *arr = @[@(10),@(20),@(5),@(60),@(22),@(13)];
NSInteger leftSum = ((NSNumber *)arr[0]).integerValue;
for (NSInteger i = 0; i < arr.count; i ++) {
sum += ((NSNumber *)arr[i]).integerValue;
}
for (NSInteger i = 1; i < arr.count - 1; i ++) {
if (2 * leftSum == (sum - ((NSNumber *)arr[i]).integerValue)) {
index = i;
break;
}
leftSum += ((NSNumber *)arr[i]).integerValue;
}
return index;

8进制 转 10进制 转 26进制

描述

输入一个 8 进制数,转换为相应的 a-z 的字符串,a 对应 1 ,z 对应 26,aa 对应 27,aaa 对应 703。
例:
输入 32,输出 z

解题思路

这个题其实描述让我头大了一会,其实这之间存在了 10 进制的中间进制,比如 a-z 对应 1-26 ,27 对应 aa ,27 其实是 10 进制,那这道题我理解的考察思路是 8 进制转换为 10 进制,然后再转化为 伪26进制 ,为啥有个 伪 呢,我们平常接触到的 2 进制,8 进制,都是从 0 开始的,例如 8 进制 : 0 1 2 3 4 5 6 7 10 11 … 从 0 开始,到达 7 以后进一位,但是这个 a-z,反而从 1 开始 ,到 26 结束。

  1. 8 进制转化为 10 进制
  2. 10 进制转化为 26 进制
  3. 得到的数,再去从低位到高位依次匹配

第三部分的匹配,有个问题,那就是 10 进制 26,转化为 26 进制是 10 ,怎么去跟 z 匹配呢,延伸出来的问题,就是 0 这个数,用哪个字符代表呢?比如 26 * 26 = 676,转化为 26 进制为 100,用什么字符串代表呢?题中没有给出描述,我还没有得出好的解决思路。

银行顾客等待时间

描述

银行有 4 个柜台,已知每个客户到达时间为数组 a ,每个客户处理时间为数组 p ,每个柜台一次只能接待一个客户,每次叫号都接待排号最前的用户,求所有用户的平均等待时间。
例:
a = [1,2,3,4,4,8] p = [50,20,11,25,30,40]
输出:平均等待时间为 24/6 = 4

解题思路

我的思路是这样,因为柜台数量是固定的,每次有新的顾客来,四个里面肯定有一个最早结束的柜台,这个顾客肯定会被这个最早结束的柜台招待。问题就是怎么找到这个最早结束的柜台。
假如有 n 个柜台,我们可以创建一个固定数量为 n 的数组 a ,它里面存储着每个柜台的结束点,即为 到达时间+处理时间,每次来了顾客,接待这个顾客的肯定是最小结束点所在的柜台,用 到达点 去跟 最小结束点 比较,假如大于 最小结束点,就表示不需要等待,否则需要等待,等待时间为 最小结束点减去到达点,同时需要刷新最小结束点,并且更新这个最小结束点为新的结束点(加上处理时间),并求出新的最小结束点,因为有可能会有变化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
{
NSArray <NSNumber *>*a = @[@(1),@(2),@(3),@(4),@(4),@(8)];
NSArray <NSNumber *>*p = @[@(50),@(20),@(11),@(25),@(4),@(40)];
NSMutableArray <NSNumber *>*endTimeArr = [NSMutableArray new];
NSInteger n = 4; /// 柜台数
NSInteger waitSum = 0; /// 等待总时间
NSInteger minEndTimeIndex = 0; /// 最小结束点下标

/// 初始化结束点数组
for (NSInteger i = 0; i < n; i ++) {
[endTimeArr addObject:[NSNumber numberWithInteger:a[i].integerValue + p[i].integerValue]];
}
/// 初始化最小结束点下标
minEndTimeIndex = [self findMinestIndex:endTimeArr];

/// 循环剩下的元素
for (NSInteger i = n; i < a.count; i ++) {
/// 假如该到达点小于最小结束点,说明需要等待,等待时间为两者差。
if (a[i].integerValue < endTimeArr[minEndTimeIndex].integerValue) {
waitSum += endTimeArr[minEndTimeIndex].integerValue - a[i].integerValue;
}
/// 更新这个下标所在的值,增加处理时间。
endTimeArr[minEndTimeIndex] = [NSNumber numberWithInteger:endTimeArr[minEndTimeIndex].integerValue + p[i].integerValue];
/// 更新最小结束点下标,因为增加处理时间后,可能会发生变化了,面试的时候我竟然晕了???
minEndTimeIndex = [self findMinestIndex:endTimeArr];
}

CGFloat averageWaitTime = (float)waitSum / n;
return averageWaitTime;
}

- (NSInteger)findMinestIndex:(NSArray <NSNumber *>*)arr
{
NSInteger index = 0;
for (int i = 1; i < arr.count; i ++) {
if (arr[i].integerValue < arr[index].integerValue) {
index = i;
}
}
return index;
}

上面是具体的 OC 代码,这个题还是挺简单的,但是面试的时候,让人问晕了 T_T ,明明已经实现出来的代码,讲的时候竟然还能讲迷糊。

面试题

介绍一下你自己

我叫侯文杰,92 年出生,14 年 毕业于山东理工大学计算机科学与技术专业,从事 iOS 开发已经 4 年了,之前做的项目都是电商类的,最近的一次工作经历是在地球港,作为 iOS 开发小组的组长,我们团队不是特别多,3 个人,我负责整个项目前期架构的搭建和优化,开发期间进行业务需求的评审,分配任务,完成项目的主要购买流程,并负责同事代码的 review ,打包上线。

离职原因

跟我的职业发展规划有点不符合吧,因为一直在小公司,小规模的团队,虽然可以培养解决问题的能力,但是眼界上得不到提升,很多问题不上升到一定规模,不会暴露出来,所以我想接触大型团队,感受下专业团队开发的氛围,让自己更加专业吧。
职业规划:毕业这几年积累技术,30 岁之前熟悉规模化的开发流程,做到 30 岁成为一个技术专家,可以带团队。

作为开发小组 leader ,你觉得最重要职责的是什么

作为小组 leader ,主要的工作不再仅仅是开发,而是要对项目做到 可控 ,简单来说就是要对每次开发周期自己有把控。

  1. 最开始的需求评审:找到需求的不合理地方,需要明确的地方,也包括后端接口是不是支持。
  2. 针对每个人进行开发任务的分配,要做到对每个人的具体工作能力有深入了解,而且把需求具体化,任务化,能够做到按时间划分。
  3. 任务优先级,每次开发周期可能有不同的需求同时进来,我们要理清哪个优先级是最高的。
  4. 关注开发进度,实时关注开发进度,遇到问题都要实时暴露出来去找解决办法。

项目概况 团队人数 负责的项目个数

针对于购物车的缓存方案实现及具体流程

针对于界面的具体优化

CPU 的密集使用

  1. 对象创建、调整、销毁
  2. 布局计算,autolayout 提前计算,防止大量调整,尽量使用 frame
  3. 文本计算渲染 可以通过后台线程 CoreText
  4. 图片解码,图片设置到 ImageView 中或者 CALayer 中时,才会解码,可以事先绘制到 CGBitmapContext 中,需要的时候直接创建图片。

GPU 的消耗原因

GPU 主要负责纹理的变换、混合、渲染

  1. 纹理的渲染 尽量减少短时间内大量图片的显示
  2. 减少视图的层次和数量

经验教训

可以看出来,这家公司问的都是 算法 + 具体项目 ,丝毫没有考察 OC 相关的东西,说明面试官应该不是 iOS 开发人员,嗯,,心理素质还不行吧,自从讲解迷糊之后,脑袋转不动了哈哈,这几天我的准备偏向于 OC 底层跟基础,还是得拿出点时间针对于自己的项目做优化和准备。
比如:数据库的线程安全,购物车缓存的实现,UI 的优化。