[iOS面試]第11章 算法相關(guān)面試問題

注意:本文主講算法相關(guān)面試問題,包括字符串反轉(zhuǎn)、鏈表反轉(zhuǎn)、有序數(shù)組合并、Hash算法、查找兩個(gè)子視圖的共同父視圖、求無序數(shù)組當(dāng)中的中位數(shù)。

一、字符串反轉(zhuǎn)

問題:給定字符串"hello, world", 實(shí)現(xiàn)將其反轉(zhuǎn).輸出結(jié)果: dlrow,oleh

字符串反轉(zhuǎn)

答:

void char_reverse(char* cha) {
    // 指向第一個(gè)字符
    char* begin = cha;
    // 指向最后一個(gè)字符
    char* end = cha + strlen(cha) - 1;
    
    while (begin < end) {
        // 交換前后兩個(gè)字符,同時(shí)移動(dòng)指針
        char temp = *begin;
        *(begin++) = *end;
        *(end--) = temp;
    }
}

//1.字符串反轉(zhuǎn)
char ch[] = "hello,world";
char_reverse(ch);
printf("reverse result is %s \n", ch);
//打印 reverse result is dlrow,olleh

二、鏈表反轉(zhuǎn)

鏈表頭插法思想

鏈表反轉(zhuǎn)
  • ReverseList.h
//ReverseList.h
// 定義一個(gè)鏈表
struct Node {
    int data;
    struct Node *next;
};
@interface ReverseList : NSObject
// 鏈表反轉(zhuǎn)
struct Node* reverseList(struct Node *head);
// 構(gòu)造一個(gè)鏈表
struct Node* constructList(void);
// 打印鏈表中的數(shù)據(jù)
void printList(struct Node *head);
@end
  • ReverseList.m
//ReverseList.m
@implementation ReverseList
struct Node* reverseList(struct Node *head) {
    // 定義遍歷指針,初始化為頭結(jié)點(diǎn)
    struct Node *p = head;
    // 反轉(zhuǎn)后的鏈表頭部
    struct Node *newH = NULL;
    
    // 遍歷鏈表
    while (p != NULL) {
        
        // 記錄下一個(gè)結(jié)點(diǎn)
        struct Node *temp = p->next;
        // 當(dāng)前結(jié)點(diǎn)的next指向新鏈表頭部
        p->next = newH;
        // 更改新鏈表頭部為當(dāng)前結(jié)點(diǎn)
        newH = p;
        // 移動(dòng)p指針
        p = temp;
    }
    // 返回反轉(zhuǎn)后的鏈表頭結(jié)點(diǎn)
    return newH;
}

struct Node* constructList(void) {
    // 頭結(jié)點(diǎn)定義
    struct Node *head = NULL;
    // 記錄當(dāng)前尾結(jié)點(diǎn)
    struct Node *cur = NULL;
    
    for (int i = 1; i < 5; i++) {
        struct Node *node = malloc(sizeof(struct Node));
        node->data = i;
        
        // 頭結(jié)點(diǎn)為空,新結(jié)點(diǎn)即為頭結(jié)點(diǎn)
        if (head == NULL) {
            head = node;
        }
        // 當(dāng)前結(jié)點(diǎn)的next為新結(jié)點(diǎn)
        else{
            cur->next = node;
        }
        // 設(shè)置當(dāng)前結(jié)點(diǎn)為新結(jié)點(diǎn)
        cur = node;
    }
    return head;
}

void printList(struct Node *head){
    struct Node* temp = head;
    while (temp != NULL) {
        printf("node is %d \n", temp->data);
        temp = temp->next;
    }
}
@end
  • 執(zhí)行調(diào)用
//單鏈表反轉(zhuǎn)
struct Node* head = constructList();
printList(head);
printf("-----------\n");
struct Node* newHead = reverseList(head);
printList(newHead); 

三、有序數(shù)組合并

有序數(shù)組合并
// 將有序數(shù)組a和b的值合并到一個(gè)數(shù)組result當(dāng)中,且仍然保持有序
void mergeList(int a[], int aLen, int b[], int bLen, int result[]) {
    int p = 0; // 遍歷數(shù)組a的指針
    int q = 0; // 遍歷數(shù)組b的指針
    int i = 0; // 記錄當(dāng)前存儲位置
    
    // 任一數(shù)組沒有到達(dá)邊界則進(jìn)行遍歷
    while (p < aLen && q < bLen) {
        // 如果a數(shù)組對應(yīng)位置的值小于b數(shù)組對應(yīng)位置的值
        if (a[p] <= b[q]) {
            // 存儲a數(shù)組的值
            result[i] = a[p];
            // 移動(dòng)a數(shù)組的遍歷指針
            p++;
        }else{
            // 存儲b數(shù)組的值
            result[i] = b[q];
            // 移動(dòng)b數(shù)組的遍歷指針
            q++;
        }
        // 指向合并結(jié)果的下一個(gè)存儲位置
        i++;
    }
    
    // 如果a數(shù)組有剩余
    while (p < aLen) {
        // 將a數(shù)組剩余部分拼接到合并結(jié)果的后面
        result[i] = a[p++];
        i++;
    }
    
    // 如果b數(shù)組有剩余
    while (q < bLen) {
        // 將b數(shù)組剩余部分拼接到合并結(jié)果的后面
        result[i] = b[q++];
        i++;
    }
}
  • 執(zhí)行調(diào)用
int a[5] = {1,4,6,7,9};
int b[8] = {2,3,5,6,8,10,11,12};

//用于存儲歸并結(jié)果
int result[13];
//歸并操作
mergeList(a, 5, b, 8, result);
//打印歸并結(jié)果
printf("merge result is ");
for (int i = 0; i < 13; i++) {
      printf("%d ", result[i]);
}
//輸出 merge result is 1 2 3 4 5 6 6 7 8 9 10 11 12 

四、Hash算法

問題:在一個(gè)字符串中找到第一個(gè)只出現(xiàn)一次的字符
如:輸入"abaccdeff" , 則輸出b

算法思想:

  • 字符(char)是一個(gè)長度為8的數(shù)據(jù)類型,因此總共有可能256中可能.
  • 每個(gè)字母根據(jù)其ASCII碼值作為數(shù)組的下標(biāo)對應(yīng)數(shù)組的一個(gè)數(shù)字.
  • 數(shù)組中存儲的是每個(gè)字符出現(xiàn)的次數(shù).

哈希表
例: 給定值是字母a, 對應(yīng)ASCII值是97, 數(shù)組索引下標(biāo)為97.
哈希函數(shù): 建立字母或字符到它所存儲位置index的一個(gè)映射關(guān)系. f(key)
存儲和查找都通過該函數(shù), 有效提高查找效率.
f(char) => index

//查找第一個(gè)只出現(xiàn)一次的字符
char findFirstChar(char* cha) {
    char result = '\0';
    // 定義一個(gè)數(shù)組 用來存儲各個(gè)字母出現(xiàn)次數(shù)
    int array[256];
    // 對數(shù)組進(jìn)行初始化操作
    for (int i=0; i<256; i++) {
        array[i] =0;
    }
    // 定義一個(gè)指針 指向當(dāng)前字符串頭部
    char* p = cha;
    // 遍歷每個(gè)字符
    while (*p != '\0') {
        // 在字母對應(yīng)存儲位置 進(jìn)行出現(xiàn)次數(shù)+1操作
        array[*(p++)]++;
    }
    
    // 將P指針重新指向字符串頭部
    p = cha;
    // 遍歷每個(gè)字母的出現(xiàn)次數(shù)
    while (*p != '\0') {
        // 遇到第一個(gè)出現(xiàn)次數(shù)為1的字符,打印結(jié)果
        if (array[*p] == 1) {
            result = *p;
            break;
        }
        // 反之繼續(xù)向后遍歷
        p++;
    }
    return result;
}
  • 執(zhí)行結(jié)果
char cha[] = "abaccdeff";
char fc = findFirstChar(cha);
printf("this char is %c \n", fc);
//輸出this char is b

五、查找兩個(gè)子視圖的共同父視圖

  • 倒序比較找到第一個(gè)不一樣的
- (NSArray <UIView *> *)findCommonSuperView:(UIView *)viewOne other:(UIView *)viewOther {
    NSMutableArray *result = [NSMutableArray array];
    
    // 查找第一個(gè)視圖的所有父視圖
    NSArray *arrayOne = [self findSuperViews:viewOne];
    // 查找第二個(gè)視圖的所有父視圖
    NSArray *arrayOther = [self findSuperViews:viewOther];
    
    int i = 0;
    // 越界限制條件
    while (i < MIN((int)arrayOne.count, (int)arrayOther.count)) {
        // 倒序方式獲取各個(gè)視圖的父視圖
        UIView *superOne = [arrayOne objectAtIndex:arrayOne.count - i - 1];
        UIView *superOther = [arrayOther objectAtIndex:arrayOther.count - i - 1];
        
        // 比較如果相等 則為共同父視圖
        if (superOne == superOther) {
            [result addObject:superOne];
            i++;
        }
        // 如果不相等,則結(jié)束遍歷
        else{
            break;
        }
    }
    
    return result;
}

- (NSArray <UIView *> *)findSuperViews:(UIView *)view {
    // 初始化為第一父視圖
    UIView *temp = view.superview;
    // 保存結(jié)果的數(shù)組
    NSMutableArray *result = [NSMutableArray array];
    while (temp) {
        [result addObject:temp];
        // 順著superview指針一直向上查找
        temp = temp.superview;
    }
    return result;
}

六、求無序數(shù)組當(dāng)中的中位數(shù)

方案:

  • 1>排序算法+中位數(shù)
  • 2>利用快排思想(分治思想)

排序算法+中位數(shù)

  • 排序算法: 冒泡排序, 快速排序, 堆排序...
  • 中位數(shù):
    當(dāng)n為奇數(shù)時(shí), (n+1)/2 ;
    當(dāng)n為偶數(shù)時(shí), (n/2 + (n/2 + 1)) / 2 ;

快排思想

快排思想
  • 快排思想: 選取關(guān)鍵字, 高低交替掃描

任意挑一個(gè)元素, 以該元素為支點(diǎn), 劃分集合為兩部分.
如果左側(cè)集合長度恰為 (n- 1)/2, 那么支點(diǎn)恰為中位數(shù).
如果左側(cè)長度恰 < (n- 1)/2, 那么中位點(diǎn)在右側(cè); 反之, 中位數(shù)在左側(cè).
進(jìn)入相應(yīng)的一側(cè)繼續(xù)尋找中位點(diǎn)

int findMedian(int a[], int aLen) {
    int low = 0;
    int high = aLen - 1;
    
    int mid = (aLen - 1) / 2;
    int div = PartSort(a, low, high);
    
    while (div != mid){
        if (mid < div){
            //左半?yún)^(qū)間找
            div = PartSort(a, low, div - 1);
        }
        else{
            //右半?yún)^(qū)間找
            div = PartSort(a, div + 1, high);
        }
    }
    //找到了
    return a[mid];
}

int PartSort(int a[], int start, int end) {
    int low = start;
    int high = end;
    
    //選取關(guān)鍵字
    int key = a[end];
    
    while (low < high) {
        //左邊找比key大的值
        while (low < high && a[low] <= key){
            ++low;
        }
        
        //右邊找比key小的值
        while (low < high && a[high] >= key){
            --high;
        }
        
        if (low < high){
            //找到之后交換左右的值
            int temp = a[low];
            a[low] = a[high];
            a[high] = temp;
        }
    }
    
    int temp = a[high];
    a[high] = a[end];
    a[end] = temp;
    
    return low;
}
  • 執(zhí)行調(diào)用
int list[9] = {12,3,10,8,6,7,11,13,9};
// 3 6 7 8 9 10 11 12 13
//             ^
int median = findMedian(list, 9);
printf("the median is %d \n", median);
// the median is 9 
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容