日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Find the Kth number(找第K大数)

發布時間:2023/12/9 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Find the Kth number(找第K大数) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目再現

題目內容: 給定N個排序好的序列,每個序列內有M個數字。因此我們總共有N*M個數字,編號為1~N*M。 將N*M個數字排序后輸出第K個數字是多少。Hint : 直接將N*M個數字做排序會超過時間限制。 Hint : 每次花O(N)的時間找一個數字,一直找到第K個數字也會超過時間限制。 Hint : 使用一個大小為N的heap,記錄每個序列目前最小的數字是多少,以及這是該序列的第幾個數字。 Hint : 不要將N*M個數字都產生出來,會超過memory限制。輸入格式: 只有一筆測資。第一行有三個數字N M K,意義如題目所述。接下來的N行,每行有2個數字a b,代表一個f(x) = ax+b。這一行的序列即為[f(1), f(2), … , f(M)]。你可以假設每一行的f(x)都會是一個遞增函數,使得你的序列肯定是排序好的序列(由小到大)。數字范圍: 0 < N <= 17000 0 < M <= 100000 <= a,b <= 100輸出格式: 輸出一行數字,第K個數字是多少。輸入樣例: 3 3 7 1 3 2 2 3 1輸出樣例: 7 時間限制:500ms內存限制:128000kb

問題解決

解法一

解決這種第K大的問題,想到的第一點就是用堆排序的方式,堆的大小為K,如果要找第K小的數,就建立最大堆;如果要找第K大的數,就要建立最小堆。所以我的解法一就是建立一個K大的最大堆,堆頂就是要求的第K小的數。

#include <stdio.h>int arrHeap[1000000]; int n = 0; // heap positionvoid swap(x, y){ int t; t = arrHeap[x]; arrHeap[x] = arrHeap[y]; arrHeap[y] = t; } void shiftDown(int x){ int t, flag = 0; while(x * 2 <= n && flag == 0){ if(arrHeap[x * 2] > arrHeap[x]){ t = x * 2; }else{ t = x; } if(x * 2 + 1 <= n){ if(arrHeap[x * 2 + 1] > arrHeap[t]){ t = x * 2 + 1; } } if(t == x){ flag = 1; }else{ swap(x, t); x = t; } } } void creatHeap(){ int i; for(i = n / 2; i >= 1; i--){ shiftDown(i); } } int main(){int N, M, K;int a, b, i, tmp; scanf("%d %d %d", &N, &M, &K);while(N --){scanf("%d %d", &a, &b);for(i = 1; i <= M; i ++){tmp = a * i + b;if(n <= K - 1){arrHeap[++ n] = tmp;if( n == K){creatHeap();}}else if(tmp < arrHeap[1]){arrHeap[1] = tmp;shiftDown(1);}}}printf("%d", arrHeap[1]);return 0; }

算法是沒問題的,對于測試樣例也是正確的,但是題目有時間限制,而要計算的數值又很大,我的算法是O(MN),所以超時 沒有通過。

解法二

其實,題目中說過一點,給出N個M長度的序列,而且每個序列都是按照升序的方式排列好的,所以為了降低時間復雜度,可以不用堆排序,而用優先隊列的方式進行,然后出隊K - 1個,那么第K個數就是隊頭了,那么怎么建立這個優先隊列呢?應該怎樣進行存儲呢?其實這就是問題的關鍵,根據題意,我們只需要按列的方式進行入隊即可輕松完成,時間復雜度是O(NlogN)。

#include <stdio.h> #include <stdlib.h>//用于存儲N * M 個結點類型 struct Item{int value;int indexRow;int indexCol; };//優先隊列(沒辦法C語言里面沒有C++那樣的STL,只能自已去寫這個) struct Queen{struct Item value;struct Queen *next; }; struct Item qTop(struct Queen **head){return (*head)->value; }void qPop(struct Queen **head){struct Queen *qTemp;if((*head) != NULL){qTemp = *head;(*head) = (*head)->next;free(qTemp); } }void qPush(struct Queen **head, struct Item x){struct Queen *newNode, *qHead, *curr;curr = qHead = *head;newNode = (struct Queen *)malloc(sizeof(struct Queen));newNode->value = x;if(qHead == NULL || qHead->value.value > newNode->value.value){newNode->next = qHead;qHead = newNode;}else{while(1){if(curr->next == NULL || curr->next->value.value > newNode->value.value){newNode->next = curr->next;curr->next = newNode;break;}else{curr = curr->next;}}}*head = qHead; }int main(){struct Queen *qHead = NULL;int N, M, K; int i, j;struct Item tmpItem;scanf("%d %d %d", &N, &M, &K); //給輸入的a, b建表int arrAB[N][2]; for(i = 0; i < N; i ++){scanf("%d %d", &arrAB[i][0], &arrAB[i][1]);} //初始化隊列for(i = 0; i < N; i ++){tmpItem.value = arrAB[i][0] + arrAB[i][1];tmpItem.indexRow = i;tmpItem.indexCol = 1;qPush(&qHead, tmpItem);}//執行 K-1 次出隊,在這個過程中不斷添加下一個結點 for(i = 0; i < K - 1; i ++){tmpItem = qTop(&qHead);qPop(&qHead);if(tmpItem.indexCol + 1 <= M){ //防止K值過大超出范圍 (可不加) tmpItem.indexCol ++;tmpItem.value = arrAB[tmpItem.indexRow][0] * tmpItem.indexCol + arrAB[tmpItem.indexRow][1];qPush(&qHead, tmpItem);}} //OK,第K小個數找到printf("%d", qTop(&qHead).value); return 0; }

因為優先隊列的操作是我個人寫的,所以要比C++ STL中的優先隊列效率要差一點,C++用戶可以直接使用STL操作,C用戶如果想自己實現也可參考我寫的。

博客名稱:王樂平博客
博客地址:http://blog.lepingde.com
CSDN博客地址:http://blog.csdn.net/lecepin



總結

以上是生活随笔為你收集整理的Find the Kth number(找第K大数)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。