java程序員進大廠算法面試中的首尾指針技巧

指針首尾並進

  1. 快排分割數組首尾的實現方式。
  2. 輸入一個整數數組,調整數組中數字的順序,使得所有奇數位於數組的前半部分,所有偶數位於數組的後半部分。要求時間複雜度爲O(n)。
  3. 輸入一個增序數組和一個數sum,在數組中找到兩個數,使得和爲sum。輸入任意一對即可。

1、思路:

先隨機選base,與尾交換。然後從左往右遍歷,找到比base大的數,交換;從右往左遍歷,找到比base小的數,交換。

#include <iostream> 
#include <exception> 
#include <stdlib.h> 
#include <string.h> 

using namespace std; 

int RandInRange(int a, int b) { 
    return rand()%(b - a + 1) + a; 
} 

void PrintArray(int data[], int length) { 
    for (int i = 0; i < length; i++) 
    printf("%d ", data[i]); 
    printf("\n"); 
}

int Partition(int data[], int length, int start, int end) { 
    if (data == NULL || length <= 0 || start < 0 || end >= length) 
    throw new exception(); 

    int index = RandInRange(start, end); 
    int base = data[index]; 
    swap(data[start], data[index]); 

    while(start < end) { 
        while (start < end && data[end] > base) 
        end--; 
        data[start] = data[end]; 
        while (start < end && data[start] < base) 
        start++; 
        data[end] = data[start]; 
    } 

    data[start] = base; 
    return start; 
} 

void QuickSort(int data[], int length, int start, int end) { 
    if (start == end) 
    return; 
    int index = Partition(data, length, start, end); 
    if (index > start) 
    QuickSort(data, length, start, index - 1); 
    if (index < end) 
    QuickSort(data, length, start + 1, end); 
} 

int main() { 
    int test[7] = {23, 13, 49, 6, 31, 19, 28}; 
    PrintArray(test, 7); 
    QuickSort(test, 7, 0, 6); 
    PrintArray(test, 7); 60 
}

2、思路:

設置兩個指針,首尾位置。首指針往後移直到遇到偶數,尾指針往前移直到遇到奇數,兩者都遇到的情況下互換位置,終止條件是首尾指針碰頭。

void ReorderOddEven(int *pData, unsigned int length) { 
    if(pData == NULL || length == 0) 
    return; 

    int *pBegin = pData; 
    int *pEnd = pData + length - 1; 

    while(pBegin < pEnd) { 
        // 向後移動pBegin,直到它指向偶數 
        while(pBegin < pEnd && (*pBegin & 0x1) != 0) 
        pBegin ++; 

        // 向前移動pEnd,直到它指向奇數 
        while(pBegin < pEnd && (*pEnd & 0x1) == 0) 
        pEnd --; 

        if(pBegin < pEnd) { 
        int temp = *pBegin; 
        *pBegin = *pEnd; 
        *pEnd = temp; 
        } 
    } 
}

3、思路:

如果原數組是無序的,則先排序,O(nlogn)開銷。這裏已經是增序排列了,所以不需要排序。設置兩個指針,一頭一尾。當和大於s,尾指針往前移;當和小於s,頭指針往後移。直到兩指針相遇,看是否有符合要求的數出現。


 
FindNumbersWithSum 
bool FindNumbersWithSum(int data[], int length, int sum, int *num1, int *num2) { 
    bool found = false; 
    if (length < 1 || num1 == NULL || num2 == NULL) 
    return found; 
    int ahead = length - 1; 
    int behind = 0; 
    while (ahead > behind) { 
        long long curSum = data[ahead] + data[behind]; 
        if (curSum == sum) { 
            *num1 = data[behind]; 
            *num2 = data[ahead]; 
            found = true; 
            break; 
        } else if (curSum > sum) 
            ahead--; 
            else 
            behind++; 
    } 
    return found; 
}

最後總結

  1. 能用首尾指針技巧解決的問題,往往序列是存在規律的,但其實這種要求並不嚴格
  2. 但是要求首尾指針根據制定的規則往中間移動的過程中,一定不會錯過答案
  3. 制定的規則與數據狀況和問題本身相關

左程雲左神:算法面試中的首尾指針技巧

ps:不瞭解左神的朋友可以去百度一下

1:介紹首尾指針技巧

2:詳解兩道利用首尾指針技巧解決的題

左程雲左神的《程序員代碼面試指南 IT名企算法與數據結構題目最優解》

字節跳動Java崗算法面試有多難?看完這些你就知道了

目錄(算法有分 將、校、尉、士四個等級來表示難易程度)

第1章棧和隊列

設計一個有getMin功能的棧(士★)

由兩個棧組成的隊列(尉★★)

如何僅用遞歸函數和棧操作逆序一個棧(尉★★)

貓狗隊列(士★)

用一個棧實現另一個棧的排序(士★)

用棧來求解漢諾塔問題(校★★★)

生成窗口最大值數組(尉★★)

構造數組的MaxTree (校★★★)

求最大子矩陣的大小(校★★★)

最大值減去最小值小於或等於num的子數組數量(校★★★)

限於篇幅原因,同時也爲了大家更好的閱讀,只截取了部分目錄,感興趣的朋友可以幫忙轉發文章後,關注私信回覆【學習】來免費獲取

字節跳動Java崗算法面試有多難?看完這些你就知道了

 

字節跳動Java崗算法面試有多難?看完這些你就知道了

 

字節跳動Java崗算法面試有多難?看完這些你就知道了

 

第1章棧和隊列

設計一個有getMin功能的棧(士★)

字節跳動Java崗算法面試有多難?看完這些你就知道了

 

字節跳動Java崗算法面試有多難?看完這些你就知道了

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章