記錄一些常見的算法題

字符串反轉

主邏輯: 兩個指針,指向頭部和末尾,而後作交換,交換完成後頭部指針向後移動,尾部指針向前移動,繼續交換,直到頭部指針地址大於尾部指針地址。node

char *begin = cha;
    char *end   = cha + strlen(cha) - 1;
    
    while (begin < end) {
        // 核心邏輯 -- 換值 移動
        char ws_tmp = *begin;
        *(begin++)  = *end;
        *(end--)    = ws_tmp;
    }
複製代碼

鏈表反轉

主邏輯: 假設原鏈表爲A->B->C->D->NULL,那麼咱們須要新建一個鏈表NULL,而後對原鏈表就行遍歷,讓每個元素的Next指向新的鏈表。具體流程:先遍歷到A,而後新鏈表變爲A->NULL,再遍歷到B,新鏈表變爲B->A->NULL,以此類推...,最終獲得翻轉鏈表D->C->B->A->NULL算法

// 定義一個鏈表
struct WSNode {
    int index;
    struct WSNode *next;
}
複製代碼
// 建立鏈表
struct WSNode* constructList(void)
{
    // 頭結點定義
    struct WSNode *head = NULL;
    // 記錄當前尾結點
    struct WSNode *cur = NULL;
    
    for (int i = 1; i < 5; i++) {
        struct WSNode *node = malloc(sizeof(struct WSNode));
        node->index = i;
        
        // 頭結點爲空,新結點即爲頭結點
        if (head == NULL) {
            head = node;
        }
        // 當前結點的next爲新結點
        else{
            cur->next = node;
        }
        // 設置當前結點爲新結點
        cur = node;
    }
    
    return head;
}
複製代碼
// 反轉鏈表
struct WSNode* reverseList(struct WSNode *head)
{
    // 定義遍歷指針,初始化爲頭結點
    struct WSNode *p = head;
    // 反轉後的鏈表頭部
    struct WSNode *newH = NULL;
    // 遍歷鏈表
    while (p != NULL) {
        // 記錄下一個結點
        struct WSNode *temp = p->next;
        // 當前結點的next指向新鏈表頭部
        p->next = newH;
        // 更改新鏈表頭部爲當前結點
        newH = p;
        // 移動p指針
        p = temp;
    }
    
    // 返回反轉後的鏈表頭結點
    return newH;
}
複製代碼

有序數組的合併

主邏輯: 假設有數組A、B,新建數組C,長度爲A+B,定義兩個指針p和q,用來遍歷A和B,再定義一個下標i來記錄當前C的存儲位置,開始遍歷,若是A[p]<=B[q],那麼把A[p]存放在C的i下標,而後p++,不然就是把B[q]存放到C的i下標,進行p++,最後A或者B遍歷完後,將另一個未遍歷完的剩餘的數據添加到C的尾部。數組

//有序數組的合併,五個參數分別表明 數組A A的長度 數組B B的長度 數組C
void mergeList(int a[], int aLen, int b[], int bLen, int result[])
{
    int p = 0; // 遍歷數組a的指針
    int q = 0; // 遍歷數組b的指針
    int i = 0; // 記錄當前存儲位置
    
    // 任一數組沒有到達邊界則進行遍歷
    while (p < aLen && q < bLen) {
        // 若是a數組對應位置的值小於b數組對應位置的值
        if (a[p] <= b[q]) {
            // 存儲a數組的值
            result[i] = a[p];
            // 移動a數組的遍歷指針
            p++;
        }
        else{
            // 存儲b數組的值
            result[i] = b[q];
            // 移動b數組的遍歷指針
            q++;
        }
        // 指向合併結果的下一個存儲位置
        i++;
    }
    
    // 若是a數組有剩餘
    while (p < aLen) {
        // 將a數組剩餘部分拼接到合併結果的後面
        result[i] = a[p++];
        i++;
    }
    
    // 若是b數組有剩餘
    while (q < bLen) {
        // 將b數組剩餘部分拼接到合併結果的後面
        result[i] = b[q++];
        i++;
    }
}
複製代碼

查找字符串中第一個只出現一個的字符

主邏輯: 使用哈希,char類型是8位,因此有2^8種可能,創建一個256位的數組來記錄每一個字符出現的次數,下標爲字符對應的ASCII碼值,值爲對應出現的次數,而後進行字符串遍歷,對數組進行設定。bash

char findFirstChar(char* cha)
{
    char result = '\0';
    // 定義一個數組 用來存儲各個字母出現次數
    int array[256];
    // 初始化
    for (int i=0; i<256; i++) {
        array[i] = 0;
    }
    
    // 定義一個指針 指向當前字符串頭部
    char* p = cha;
    // 遍歷每一個字符
    while (*p != '\0') {
        // 在字母對應存儲位置 進行出現次數+1操做,
        // *(p++)爲哈希函數,計算對應的index
        array[*(p++)]++;
    }
    
    // 將p指針從新指向字符串頭部
    p = cha;
    // 遍歷每一個字母的出現次數
    while (*p != '\0') {
        // 遇到第一個出現次數爲1的字符,打印結果
        if (array[*p] == 1)
        {
            result = *p;
            break;
        }
        // 反之繼續向後遍歷
        p++;
    }
    
    return result;
}
複製代碼

查找兩個視圖的公共父視圖

主邏輯: 先分別遍歷獲得視圖A和視圖B的全部的父視圖Array,而後逆向遍歷兩個Array(逆序比正序少幾回遍歷比較),以下圖,從D開始遍歷函數

// 獲取view的父視圖數組
- (NSArray *)getSuperViewArrayWithView:(UIView *)view {
    NSMutableArray *superArr = NSMutableArray.array;
    
    UIView *temp = view.superview;
    while (temp) {
        [superArr addObject:temp];
        temp = temp.superview;
    }
    return superArr;
}
複製代碼
// 獲取兩個view的公共父視圖數組
- (NSArray *)getCommonSuperViewWith:(UIView *)viewA andView:(UIView *)viewB {
    NSMutableArray *commonArr = NSMutableArray.array;
    
    NSArray *AArray = [self getSuperViewArrayWithView:viewA];
    NSArray *BArray = [self getSuperViewArrayWithView:viewB];
    
    for (int i = AArray.count - 1; i >= 0; i--) {
        Class targetClass = AArray[i];
        for (int j = BArray.count - 1; j >= 0; j--) {
            if (targetClass == BArray[j]) {
                [commonArr addObject:targetClass];
            }
        }
    }
    
    return commonArr;
}
複製代碼

上面的算法是進行了兩個for循環的嵌套,咱們來簡化一下算法:ui

for (int i = AArray.count - 1; i >= 0; i--) {
        Class targetClass = AArray[i];
        if ([BArray containsObject:targetClass]) {
            [commonArr addObject:targetClass];
        }
    }
複製代碼

查找無序數組中的中位數

  • 什麼是中位數 : 中位數是按順序排列的一組數據中居於中間位置的數,即在這組數據中,有一半的數據比他大,有一半的數據比他小.

有一組數據:X1,X2...Xnspa

將它按從小到大的順序排序爲:X1,X2,...Xn指針

則當n爲奇數時中位數爲:X(n+1)/2 ;當N爲偶數時中位數爲(Xn/2 + X(n/2+1))/2code

主邏輯: :參考快速排序的邏輯,假設有n個數,隨機選取一個數m,而後定義兩個指針分別指向頭和尾,左邊指針取值跟m對比,比m小的話,指針日後移,右邊指針也跟m對比,比m大的話,指針往前移,這樣一次結束以後,比它小的就會放到左邊,比它大的就會放到右邊,記錄此時頭指針的下標,跟n/2相比較,若是大於n/2,那麼就繼續從左邊這部分繼續進行上面的遍歷,若是小於n/2,就從右邊繼續遍歷,直到最終頭指針的下標位置 = n/2,說明找到了中位數。cdn

// 求一個無序數組的中位數
float ws_findMid(int a[], int aLen)
{
    int low = 0;
    int high = aLen - 1;
    
    int mid = (aLen + 1) / 2 - 1;       //減一是由於下標是從0開始,奇數跟偶數這裏的mid都是同樣的算法
    int currentHeader = ws_partSort(a, low, high);
    
    while (currentHeader != mid)
    {
        if (mid < currentHeader)
        {
            //左半區間找
            currentHeader = ws_partSort(a, low, currentHeader - 1);
        }
        else
        {
            //右半區間找
            currentHeader = ws_partSort(a, currentHeader + 1, high);
        }
    }
    
    //找到了
    float midNum = a[mid];
    
    //奇偶判斷
    if(aLen %2 != 0)
        return midNum;
    
    float anotherMid = a[mid+1];
    return (midNum + anotherMid)/2.0;
}

int ws_partSort(int a[], int start, int end)
{
    int low = start;
    int high = end;
    
    //選取關鍵字
    int key = a[start];
    
    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;
        }
    }
    
    return low;
}
複製代碼
相關文章
相關標籤/搜索