215. 陣列中的第K個最大元素(快速排序)
阿新 • • 發佈:2020-12-06
思路:
快速排序
3.8 快速排序
演算法描述
演算法思想: 對給定陣列中的元素進行重新排列, 確定陣列中元素的一個位置q, 得到一個快速排序的劃分
QUICKSORT功能,將陣列A的A[p]到A[q]變為有序(比如從小到大)
QUICKSORT(A, p, r)
- if p < r
- then q \(\leftarrow\) PARTITION(A, p, r)
- QUICKSORT(A, p, q)
- QUICKSORT(A, q + 1, r)
PARTITION在A[p]到A[r]以A[p]為界劃分成兩部分A[p]的左邊比A[p]小,A[p]的右邊比A[p]大
PARTITION(A, p, r)
- x \(\leftarrow\) A[p], i \(\leftarrow\) p + 1, j \(\leftarrow\) r
- while i \(\leq\) j
- while A[j] \(\geq\) x and j \(>\) p
- j \(\leftarrow\) j -1
- while A[i] \(\leq\) x and i \(<\) r
- i \(\leftarrow\) i + 1
- if i < j then A[i] \(\leftrightarrow\) A[j]
- i \(\leftarrow\) i + 1, j \(\leftarrow\)
- A[p] $ A[j], return j
(1)快速排序演算法複雜性分析
快速排序演算法的執行時間依賴於:
- 劃分的平衡與否
- 劃分的平衡與否依賴於演算法的輸入
- 如果劃分平衡, 時間複雜性為\(O(n log n)\)
- 如果劃分不平衡, 時間複雜性為\(O(n^2)\)
最壞時間複雜性
Quicksort 的最壞情況發生在Partition 輸出的兩個區域中, 一個僅包含1 個元素, 另一個包含n - 1個元素的情況;假設上述不平衡的劃分發生在演算法的每一步迭代中, 則
\[T(n) = \begin{cases} O(1)&\text{,n} \leq {1}\\[2ex] T(n - 1) + O(n)&\text{,n > 1}\\[2ex] \end{cases} \]排序過程中每次都出現上述情況就是最壞情況
每次問題的規模只減小了1,易知時間複雜度為\(O(n^2)\)
最優時間複雜性
設如果Partition 演算法產生兩個大小為n=2 的區域,則
\[T(n) = 2T(\frac{n}{2}) + O(n) \]根據主定理, 可以得出
\[T(n) = O(n log n) \](2)隨機化快速排序演算法
- 快速排序演算法取決於劃分的對稱性
- 採用隨機策略進行劃分
- 演算法每一步在陣列A[p, r] 中隨機選出一個元素作為劃分元素, 可以期望劃分是較對稱的
RANDOMIZED-QUICKSORT演算法
RANDOMIZED-QUICKSORT(A, p, r)
- if p < r
- then q =RANDOMIZED-PATITION(A, p, r)
- RANDOMIZED-QUICKSORT(A, p, q)
- RANDOMIZED-QUICKSORT(A, q + 1, r)
RANDOMIZED-PARTITION演算法
RANDOMIZED-PARTITION(A, p, r)
- i=Random(p, r)
- exchange A[p] \(\leftrightarrow\) A[i]
- Return PARTITION(A, p, r)
程式碼如下:
package main
import (
"fmt"
"math/rand"
)
func findKthLargest(nums []int, k int) int {
left := 0
right := len(nums)-1
length :=len(nums)-k
for{
if left == right{// 迴圈終止條件
return nums[right]
}
p := partition(nums,left,right)
if p == length{
return nums[p]
}else if p<length{
left = p+1
}else{
right = p-1
}
}
}
func partition(nums []int,left int,right int)( int){
// 產生一個隨機數
randlf := right -left
rand_get := rand.Intn(randlf)
rand_fin := left+rand_get
// 將產生的隨機數對應的陣列中的元素和num[left]互換
randnum :=rand_fin
temp_1 :=nums[randnum]
temp_2 := nums[left]
nums[left],nums[randnum] = temp_1,temp_2
x := nums[left]
i := left+1
j := right
for i<=j{
for nums[j]>=x && j>left{
j = j-1
}
for nums[i]<=x && i<right{
i = i+1
}
if i<j{
temp := nums[i]
nums[i],nums[j] = nums[j],temp
i = i+1
j = j-1
}
}
t := nums[left]
nums[left],nums[j] = nums[j],t
return j
}
func main(){
nums := []int{1,2,4,5,6,7,8}
fmt.Println(findKthLargest(nums,2))
}