寫這篇文章的主要目的是記錄下bestswifter的BAT的面試問題,補充下自己的面試經驗,bestswifer的面經請看BAT面試指南。
百度
算法
不用臨時變量怎麼實現 swap(a, b)?
異或運算符^也稱XOR運算符,它的規則是若參加運算的兩個二進位同號,則結果爲0(假);異號爲1(真)。即0 ^ 0 = 0, 0 ^ 1 = 1, 1 ^ 0 = 1, 1 ^ 1 = 0。
例:
異或
#include <stdio.h>
int main(int argc, char *argv[])
{
int a = 2, b = 6;
a = a ^ b;
b = b ^ a;
a = a ^ b;
printf("a = %d b = %d/n", a, b);
return 0;
}
結果如下
a = 6 b = 2
分析:
前兩個賦值語句:“a = a ^ b;”和“b = b ^ a;”相當於b = b ^ (a ^ b),而b ^ a ^ b等於a ^ b ^ b。b ^ b的結果爲0,因爲同一個數與相向相^,結果必爲0。因此b的值等於a ^ 0,即a,其值爲2。
再執行第三個賦值語句:“a = a ^ b”。由於a的值等於(a ^ b),b的值等於(b ^ a ^ b),因此,相當於a = a ^ b ^ b ^ a ^ b,即a的值等於a ^ a ^ b ^ b ^ b,等於b。
也可以用加法來實現。
void swap(int *p, int *q)
{
*p = *p + *q;
*q = *p - *q;
*p = *p - *q;
}
原理也很簡單。
二維有序數組查找數字
詳見 劍指offer(1)-二維數組中的查找,建議最好自己再重新敲一遍代碼。
億級日誌中,查找登陸次數最多的十個用戶
佔坑~
簡述排序算法
佔坑~
iOS知識相關
說說你對 OC 中 load 方法和 initialize 方法的異同。
主要說一下執行時間,各自用途,沒實現子類的方法會不會調用父類的。
load
顧名思義,load方法在這個文件被程序裝載時調用。只要是在Compile Sources中出現的文件總是會被裝載,這與這個類是否被用到無關,因此load方法總是在main函數之前調用。所以,不管有沒有實現子類的方法,父類的方法都會被調用。
由於調用load方法時的環境很不安全,我們應該儘量減少load方法的邏輯。另一個原因是load方法是線程安全的,它內部使用了鎖,所以我們應該避免線程阻塞在load方法中。
一個常見的使用場景是在load方法中實現Method Swizzle:
initialize
這個方法在第一次給某個類發送消息時調用(比如實例化一個對象),並且只會調用一次。initialize方法實際上是一種惰性調用,也就是說如果一個類一直沒被用到,那它的initialize方法也不會被調用,這一點有利於節約資源。
即使子類沒有實現initialize方法,也會調用父類的方法。
initialize方法主要用來對一些不方便在編譯期初始化的對象進行賦值。比如NSMutableArray這種類型的實例化依賴於runtime的消息發送,所以顯然無法在編譯器初始化:
// In Parent.m
static int someNumber = 0; // int類型可以在編譯期賦值
static NSMutableArray *someObjects;
+ (void)initialize {
if (self == [Parent class]) {
// 不方便編譯期複製的對象在這裏賦值
someObjects = [[NSMutableArray alloc] init];
}
}
說說你對 block 的理解
三種 block,棧上的自動複製到堆上,block 的屬性修飾符是 copy,循環引用的原理和解決方案。
詳細資料可見
談Objective-C block的實現
block沒那麼難(一):block的實現
block沒那麼難(二):block和變量的內存管理
block沒那麼難(三):block和對象的內存管理
Block雖然知道怎麼用,但是要理解它的原理和內存管理,還是很困難的,建議看下《iOS與OS X多線程和內存管理》這本書。