前言
解這題最重要的是學習 Quick Sort 快速排序演算法是如何運作的,實作中間也可學到遞迴的概念,題目目標是把陣列從小到大排序後,找到給定的元素大小位置就是答案,在每次遞歸中我們需要線性的時間 O(n)
來進行分區操作。快速排序的遞歸樹的深度為 O(log n)
,時間複雜度估算為 O(n log n)
,這裡有 JAVA 和 Python 的寫法。
題目
Given an integer array nums
and an integer k
, return the kth
largest element in the array . Note that it is the kth
largest element in the sorted order, not the kth
distinct element. Can you solve it without sorting?
給定一個整數陣列 nums
和一個整數 k
,回傳在這個陣列裡第 k
個最大的元素 注意它是排序順序中第 k
個最大的元素,不是第 k
個不同的元素 你能不排序解決它嗎?
題目連結:https://leetcode.com/problems/kth-largest-element-in-an-array/
題目限制
1 <= k <= nums.length <= 105
104 <= nums[i] <= 104
範例
1 2 Input: nums = [3 ,2 ,1 ,5 ,6 ,4 ], k = 2 Output: 5
1 2 Input: nums = [3 ,2 ,3 ,1 ,2 ,4 ,5 ,5 ,6 ], k = 4 Output: 4
思路&筆記
解這題之前可能要先去了解一下 Quick Sort 快速排序演算法的原理,來作這題會比較好懂 不過也是可以使用語言自帶的 sort()
方法來排序完,之後再把 k 個索引減掉就是答案了 另外這題也有運用到遞迴的概念,可能也要稍微去了解一下 這題總共會寫到三個 function,第一個 quickSort()
來執行遞迴,第二個 partition()
來執行把陣列排序後找到某個元素最正確的位置,第三個 swap()
來執行元素和元素間的交換
原本的 function 來呼叫自己寫的 quickSort()
,把陣列元素從小排到大,之後陣列的長度減掉 k 個索引就是我們要的答案
執行 quickSort()
,呼叫第一次 partition()
方法會取得 pivot 的最正確的位置 ( pivot 作為中心點用於分辨左右兩邊的元素)
之後利用遞迴重複做 partition()
方法裡面的事情,partition()
方法已經做完一次排序了但還不夠完整,需要靠多次遞迴做一樣的事把小到大排序排到完整,做完第一次會把較小的元素放在 pivot 的左邊,右邊都放較大的元素 ,這裡會呼應上面所講的 pivot 的位置很重要,後續做的遞迴都是依靠這個位置在分辨左右邊的元素 (下方有示意圖可供參考)
不過做遞迴時傳進去的參數是 quickSort(nums, start, pivot - 1);
和 quickSort(nums, pivot + 1, end);
,最後會得出整個陣列以小到大的排序結果
另外也寫了 swap()
方法,用於交換元素
[備註] pivot - 1
的意思是,partition()
做第一次排序的時候 pivot 最正確的位置已經被找出來了,遞迴在往後做的時候僅只要做左半邊的部分,所以迴圈的結束點會落在 pivot 的前一個索引,右半邊原理相同,起始點從 pivot +1
開始做循環。
partition function 示意圖
1 2 3 4 5 int pivot = end; int pivotIndex = start; for (int i = start; i < end; i++){ }
1 2 3 4 5 6 7 i pivot ↓ ↓ [ 5 , 7 , 1 , 3 , 2 , 4 ] ↑ pivotIndex num[i] > num[pivot] 不做交換
1 2 3 4 5 6 7 i pivot ↓ ↓ [ 5 , 7 , 1 , 3 , 2 , 4 ] ↑ pivotIndex num[i] > num[pivot] 不做交換
1 2 3 4 5 6 7 8 9 10 i pivot ↓ ↓ [ 5 , 7 , 1 , 3 , 2 , 4 ] ↑ pivotIndex num[i] < num[pivot] num[i] 和 num[pivotIndex] 做交換 (1 跑到 5 的位置) pivotIndex++
1 2 3 4 5 6 7 8 9 10 i pivot ↓ ↓ [ 1 , 7 , 5 , 3 , 2 , 4 ] ↑ pivotIndex num[i] < num[pivot] num[i] 和 num[pivotIndex] 做交換 (3 跑到 7 的位置) pivotIndex++
1 2 3 4 5 6 7 8 9 10 i pivot ↓ ↓ [ 1 , 3 , 5 , 7 , 2 , 4 ] ↑ pivotIndex num[i] < num[pivot] num[i] 和 num[pivotIndex] 做交換 (2 跑到 5 的位置) pivotIndex++
1 2 3 4 5 6 7 8 i、pivot ↓↓ [ 1 , 3 , 2 , 7 , 5 , 4 ] ↑ pivotIndex i = end 所以 for 迴圈停止pivotIndex 和 i 做交換
1 2 3 4 5 [ 1 , 3 , 2 , 4 , 5 , 7 ] ↑ pivotIndex 陣列已排序了第一次 把 pivotIndex 回傳出去
JAVA 實現
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 class Solution { public int findKthLargest (int [] nums, int k) { quickSort(nums, 0 , nums.length - 1 ); return nums[nums.length - k]; } private void quickSort (int [] nums, int start, int end) { if (start < end) { int pivot = partition(nums, start, end); quickSort(nums, start, pivot - 1 ); quickSort(nums, pivot + 1 , end); } } private int partition (int [] nums, int start, int end) { int pivot = end; int pivotIndex = start; for (int i = start; i < end; i++){ if (nums[i] < nums[pivot]){ swap(nums, i, pivotIndex); pivotIndex++; } } swap(nums, pivotIndex, pivot); return pivotIndex; } private void swap (int [] nums, int i, int j) { int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; } }
Python 實現
使用了和 Java 一樣的邏輯執行,換成 Python 的寫法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class Solution : def findKthLargest (self, nums: List [int ], k: int ) -> int : self.quickSort(nums, 0 , len (nums) - 1 ) return nums[len (nums) - k] def quickSort (self, nums: List [int ], start:int , end:int ) -> int : if start < end: pivot = self.partition(nums, start, end) self.quickSort(nums, start, pivot - 1 ) self.quickSort(nums, pivot + 1 , end) def partition (self, nums: List [int ], start:int , end:int ) -> int : pivot = end pivotIndex = start for i in range (start, end): if nums[i] < nums[pivot]: self.swap(nums, i, pivotIndex) pivotIndex += 1 self.swap(nums, pivot, pivotIndex) return pivotIndex def swap (self, nums: List [int ], i:int , j:int ) -> int : temp = nums[i] nums[i] = nums[j] nums[j] = temp
成績
Language
Runtime
Memory
Java
138ms
54.27MB
Python
9610ms
32.34MB
參考資料
Quick Sort 快速排序:https://www.youtube.com/watch?v=mrW5OSr3OVc