劍指offer 29 最小的K個數

2021-08-31 21:10:14 字數 4599 閱讀 3382

題目:

輸入n個整數,找出其中最小的k個數。例如輸入4,5,1,6,2,7,3,8這8個數字,則最小的4個數字是1,2,3,4,。

思路分析

簡單思路:先快排,再取數;

# -*- coding:utf-8 -*-

class

solution

:def

getleastnumbers_solution

(self, tinput, k)

:# write code here

ifnot tinput:

return

if k >

len(tinput)

:return

output = self.quick_sort(tinput)

return output[

:k]def

quick_sort

(self, input_list):if

len(input_list)

<=1:

return input_list

less =

greater =

base = input_list.pop(

)for x in input_list:

if x > base:

else

:return self.quick_sort(less)

+[base]

+ self.quick_sort(greater)

基於「先整體排序,然後取前k個元素」的思路引申:需要的是前k小的數,沒必要捨近求遠把整個陣列都排好序。這樣一來,時間複雜度可以降到o(nlogk)。利用最大堆演算法,只不過在這裡稍稍將最大堆演算法變為最小堆演算法,**如下:

# -*- coding:utf-8 -*-

# 最大堆,o(nlogk)

defgetleastnumbers_solution

(self, tinput, k):if

len(tinput)

< k:

return

res =

for i in tinput:

-i)if

len(res)

-i)return

sorted

(list

(map

(lambda x:

-x, res)

))

這道題明顯是希望使用堆排序,這裡也重新對堆排序進行一次盤點,

思路:

我們可以先建立乙個大小為k的資料容器來儲存最小的k個數字,接下來我們每次從輸入的n個整數中的n個整數中讀入乙個數。如果容器中已有的數字少於k個,則直接把這次讀入的整數放入容器之中;如果容器已經有k個數字了,也就是容器滿了,此時我們不能再插入新的數字而只能替換已有的數字。找出這已有的k個數中的最大值,然後拿這次待插入的整數和最大值進行比較。如果待插入的值比當前已有的最大值小,則用這個數替換當前已有的最大值;如果待插入的值比當前已有的最大值還要大,那麼這個數不可能是最小的k個整數之一,於是我們可以拋棄這個整數。

因此當容器滿了之後,我們要做3件事情:

一是在k個整數中找到最大數;

二是有可能在這個容器中刪除最大數;

三是有可能要插入乙個新的數字。

如果用乙個二叉樹來實現這個資料容器,那麼我們在o(logk)時間內實現這三步操作。因此對於n個輸入數字而言,總的時間效率就是o(nlogk)。

c++ version:

class

solution

for(

int i =

0; i < input.

size()

; i++

)else

for(

int j = k -

1; j >

0; j--)if

(result[k-1]

> input[i])}

}return result;

}private

:void

headadjust

(vector<

int>

&input,

int parent,

int length)

if(temp >= input[child]

) input[parent]

= input[child]

;

parent = child;

child =

2* parent +1;

} input[parent]

= temp;}}

;

對於上述**,我們還可以進一步優化,不是每次迴圈都需要重新排序的,只有在更新了容器的資料之後,才需要重新排序。

class

solution

for(

int i =

0; i < input.

size()

; i++

)else

for(

int j = k -

1; j >

0; j--

) change =

false;}

if(result[k-1]

> input[i])}

}return result;

}private

:void

headadjust

(vector<

int>

&input,

int parent,

int length)

if(temp >= input[child]

) input[parent]

= input[child]

;

parent = child;

child =

2* parent +1;

} input[parent]

= temp;}}

;

python version:

# -*- coding:utf-8 -*-

class

solution

:def

headadjust

(self, input_list, parent, length)

: temp = input_list[parent]

child =

2* parent +

1while child < length:

if child +

1< length and input_list[child]

< input_list[child+1]

: child +=

1if temp >= input_list[child]

:break

input_list[parent]

= input_list[child]

parent = child

child =

2* parent +

1 input_list[parent]

= temp

defgetleastnumbers_solution

(self, tinput, k)

:# write code here

res =

length =

len(tinput)

change =

true

if length <=

0or k <=

0or k > length:

return res

res = tinput[

:k]for i in

range

(k, length+1)

:if change ==

true

:for j in

range(0

, k//2)

[::-

1]: self.headadjust(res, j, k)

for j in

range(1

, k)[:

:-1]

: res[0]

, res[j]

= res[j]

, res[0]

self.headadjust(res,

0, j)

change =

false

if i != length and res[k-1]

> tinput[i]

: res[k-1]

= tinput[i]

change =

true

return res

**解釋:

劍指Offer (29)最小的k個數

題目描述 輸入n個整數,找出其中最小的k個數。例如輸入4,5,1,6,2,7,3,8這8個數字,則最小的4個數字是1,2,3,4。實現如下 測試用例中給出的返回值是有序的。嘖嘖。找到序列中最小的k個數,利用set,對數字進行insert或erase 紅黑樹中查詢 插入 刪除操作都為 o logk 最...

劍指offer 29 最小的K個數

輸入n個整數,找出其中最小的k個數。例如輸入4,5,1,6,2,7,3,8這8個數字,則最小的4個數字是1,2,3,4。最簡單容易想到的就是先排序,然後輸出前k個數即可。但是這樣明顯時間複雜度比較高。也可以使用另外的方法,具體不再詳述。class solution for int i 0 i inp...

劍指Offer 29 最小的k個數

目錄 基礎補充 解法一 輸入陣列排序,然後取前k個 解法二 基於partition函式 解法三 最大堆 最小堆 3.1 時間複雜度o nlogn 空間複雜度o n 3.2 時間複雜度o nlogk 空間複雜度o k 解法四 紅黑樹 multiset集合 python排序實現 vector的使用方法 ...