Leetcode703. 數據流中的第K大元素(堆排序,最小堆,最大堆,快速排序,直接插入排序,數組)

鏈接:https://leetcode-cn.com/problems/kth-largest-element-in-a-stream
設計一個找到數據流中第K大元素的類(class)。注意是排序後的第K大元素,不是第K個不同的元素。
你的 KthLargest 類需要一個同時接收整數 k 和整數數組nums 的構造器,它包含數據流中的初始元素。每次調用 KthLargest.add,返回當前數據流中第K大的元素。

示例:

int k = 3;
int[] arr = [4,5,8,2];
KthLargest kthLargest = new KthLargest(3, arr);
kthLargest.add(3);   // returns 4
kthLargest.add(5);   // returns 5
kthLargest.add(10);  // returns 5
kthLargest.add(9);   // returns 8
kthLargest.add(4);   // returns 8

說明:
你可以假設 nums 的長度≥ k-1 且k ≥ 1。

改進後:

/* 思路
kthLargestCreate 時候 (快速排序)
add 之後,數據保存在 obj 中
add 之後,obj (直接插入) 不能直接用快排,浪費時間 ..

改進:
用最小堆,會更快一點 , 長度爲 k
*/

void heap_swap(int *a, int *b){
    int tmp = *a;
    *a = *b;
    *b = tmp;
}

void adjust_min_heap(int *nums, int pos, int len){
    int tmp = nums[pos]; // 臨時保存根節點
    int child = pos * 2 + 1; // 左子葉節點 (右子葉節點不一定存在)

    while(child <= len){
        pos = (child - 1) / 2;
        if(child + 1 <= len && nums[child + 1] > nums[child]){  // 找出左右子結點最大值
            child++;
        }
        if(nums[child] > tmp){ // (葉子)節點上升
            nums[pos] = nums[child];
            child = child * 2 + 1; // 往下繼續調整
        }else{
            break; // 跳出循環
        }
    }
    nums[(child - 1) / 2] = tmp;
}

void heap_sort(int *nums, int numsSize){
    // 將原始數組調整爲最小堆
    int i = 0;
    for(i = numsSize / 2 - 1; i >= 0; i--){ // 計算有子葉根節點位置 nums[i]
        adjust_min_heap(nums, i, numsSize - 1);
    }

    // 交換堆頂 ,繼續調整
    for(i = numsSize - 1; i > 0; i--){
        heap_swap(&nums[0], &nums[i]);
        adjust_min_heap(nums, 0, i - 1);
    }

}

// 調整最小堆
void heap_insert_head(int *nums, int *len){
    int tmp = nums[0];
    int pos = 0;
    int child = 1;
    while(child <= len){
        pos = (child - 1) / 2;
        if(child + 1 <= len && nums[child] > nums[child + 1]){
            child++;
        }
        if(nums[child] < tmp){
            nums[pos] = nums[child];
            child = child * 2 +1;
        }else{
            break;
        }
    }
    nums[(child - 1) / 2] = tmp;
}
/////////////////////////////////////////////////////////////////////////////


typedef struct {
    int asize;
    int *arr;
    int flag;
} KthLargest;

KthLargest* kthLargestCreate(int k, int* nums, int numsSize) {
    KthLargest *kl = (KthLargest *)calloc(1, sizeof(KthLargest));
    kl->asize = k;
    kl->arr = (int *)calloc(1, kl->asize * sizeof(int));
    kl->flag = numsSize >= k ? 0 : 1;

    int i = 0;
    // heap sort nums;
    heap_sort(nums, numsSize);

    if(0 == numsSize){
        kl->flag = 1;
        return kl;
    }

    int len = numsSize >= k ? k : numsSize;
    for(i = 0; i < len; i++){ kl->arr[k - 1 - i] = nums[numsSize - 1 - i]; }
    return kl;
}

int kthLargestAdd(KthLargest* obj, int val) {
    if(val <= obj->arr[0] && !obj->flag){
        return obj->arr[0];
    }
    obj->flag = 0;
    obj->arr[0] = val;
    heap_insert_head(obj->arr, obj->asize - 1);
    return obj->arr[0];
}

void kthLargestFree(KthLargest* obj) {
    free(obj->arr);
    free(obj);
}

改進前

void quick_sort(int* nums, int start, int end){
    if(start >= end){ return; }

    int i = start;
    int j = end;

    while(i < j){
        while(nums[j] <= nums[start] && i < j){
            j--;
        }
        while(nums[i] >= nums[start] && i < j){
            i++;
        }

        if(i < j){
            int tmp = nums[j];
            nums[j] = nums[i];
            nums[i] = tmp;
        }
    }

    // 交換基準值
    int tmp = nums[start];
    nums[start] = nums[i];
    nums[i] = tmp;

    quick_sort(nums, start, i-1);
    quick_sort(nums, i + 1, end);
}

void sort_insert(int *nums, int nums_length) {
	int i = 0;
	int j = 0;

	for (i = 1; i < nums_length; i++) {
		int tmp = nums[i];
		for (j = i - 1; j >= 0 ; j--) {
			if (tmp > nums[j]) {
				nums[j + 1] = nums[j];
			}
			else {
				break;
			}
		}
		nums[j + 1] = tmp;
	}
}

typedef struct {
    int k;     // 保存k值
    int size;  // arr 的長度
    int kvalue;// 保存第k個值,提高性能
    int *arr;
} KthLargest;

KthLargest* kthLargestCreate(int k, int* nums, int numsSize) {
    KthLargest* kl = (KthLargest *)calloc(sizeof(KthLargest), 1);
    kl->k = k;
    kl->size = numsSize;
    kl->arr = (int *)calloc(1, sizeof(int) * numsSize);

    // 快排 (從大到小)
    quick_sort(nums, 0, numsSize - 1);
    kl->kvalue = INT_MIN;

    int i = 0;
    for(i = 0; i < numsSize; i++){ kl->arr[i] = nums[i]; }

    return kl;
}

int kthLargestAdd(KthLargest* obj, int val) {
    if(val < obj->kvalue){ return obj->kvalue; } // 提高性能 
 
    obj->size = obj->size + 1 > obj->k + 1 ? obj->k + 1 : obj->size + 1;
    obj->arr = (int *)realloc(obj->arr, obj->size * sizeof(int));
    obj->arr[obj->size - 1] = val;

    // 直接插入排序 val 
    sort_insert(obj->arr, obj->size);

    obj->kvalue = obj->arr[obj->k - 1];
    return obj->kvalue;
}

void kthLargestFree(KthLargest* obj) {
    free(obj->arr);
    free(obj);
}

/**
 * Your KthLargest struct will be instantiated and called as such:
 * KthLargest* obj = kthLargestCreate(k, nums, numsSize);
 * int param_1 = kthLargestAdd(obj, val);
 
 * kthLargestFree(obj);
*/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章