TopK 問題解法

參考博客地址,詳細解釋都在此博客中

Method One:排序

排序,取前 K 個最大元素,排序的時間複雜度可以達到 O(NlogN)

//sort降序排序,取最大的K個
bool Cmp(int x, int y) {
    return x > y;
}
int* topk(int *arr, int size, int K) {
    int *ret = new int[K];
    std::sort(arr, arr + size, Cmp);
    memcpy(ret, arr, K*sizeof(int));
    return ret;
}

Method Two:局部排序

局部排序,冒泡排序的思想,但是隻排 K 次,取出最大的 K 個,時間複雜度O(N*K)

int* topk(int* arr, int size, int K) {
    int *ret = new int[K];
    for (int i = 0; i < K; ++i) {
        for (int j = 0; j < size-i-1; ++j) {
            if (arr[j] > arr[j+1]) {
                std::swap(arr[j], arr[j+1]);
            }
        }
    }
    memcpy(ret, arr+size-K, K*sizeof(int));
    return ret;
}

Method Three:堆

只找到前 K 個最大的元素,不對他們進行排序,如果運氣很差,每次都入堆調整,時間複雜度O(N*log(K))

// 向下調整
void Adjust(int *arr, int size, int parent) {
    int child = 2 * parent + 1;
    while (child < size) {
        if (child + 1 < size && arr[child] > arr[child+1]) {
            child++;
        }
        if (arr[child] < arr[parent]) {
            std::swap(arr[child], arr[parent]);
            parent = child;
            child = 2 * parent + 1;
        }
        else {
            break;
        }
    }
}

int* topk(int *arr, int size, int K)  {
    int *ret = new int[K];
    //建小堆
    int end = (K - 1) >> 1;
    while (end >= 0) {
        Adjust(arr, K, end);
        end--;
    }
    //將堆中元素換爲最大的K個
    for (int i = K; i < size; ++i) {
        if (arr[i] > arr[0])
            std::swap(arr[0], arr[i]);
        Adjust(arr, K, 0);
    }

    memcpy(ret, arr, K*sizeof(int));
    return ret;
}

Method Four:隨機選擇 +partition

和快速排序的思想類似,只要我們在用 key 分左右兩部分的時候,分界點 pos==K 說明找到了最大的K個元素(都在pos左邊)

int partion(int* arr, int begin, int end) {
    int left = begin;
    int right = end - 1;
    int key = arr[right];
    while (left < right) {
        while (arr[left] > key) {
            left++;
        }
        if (left < right) {
            arr[right] = arr[left];
            right--;
        }
        while (arr[right] < key) {
            right--;
        }
        if (left < right) {
            arr[left] = arr[right];
            left++;
        }
    }
    arr[left] = key;
    return left;
}

int* topk(int *arr, int begin, int end, int K) {
    int pos = partion(arr, begin, end);
    if (pos == K) {
        int *ret = new int[K];
        memcpy(ret, arr, K*sizeof(int));
        return ret;
    }
    else if (pos > K) {
        return topk(arr, begin, pos, K);
    }
    return topk(arr, pos+1, end, K);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章