Skip to content

Commit 3b2f146

Browse files
committed
[zh-hans en] update kth_largest_element.md: add iterative implementation
1 parent 76b4447 commit 3b2f146

File tree

3 files changed

+115
-3
lines changed

3 files changed

+115
-3
lines changed

Diff for: en/basics_sorting/quick_sort.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ The output:
286286
Having analyzed three implementations of quick sort, we may grasp one key difference between *quick sort* and *merge sort* :
287287

288288
1. Merge sort divides the original array into two sub-arrays, and merges the sorted sub-arrays to form a totally ordered one. In this case, recursion happens before processing(merging) the whole array.
289-
2. Quick sort divides the original array into two sub-arrays, and then sort them. The whole array is sorted as soon as the sub-arrays get sorted. In this case, recursion happens after processing(partition) the whole array.
289+
2. Quick sort divides the original array into two sub-arrays, and then sort them. The whole array is ordered as soon as the sub-arrays get sorted. In this case, recursion happens after processing(partition) the whole array.
290290

291291
Robert Sedgewick's presentation on [quick sort](http://algs4.cs.princeton.edu/23quicksort/) is strongly recommended.
292292

Diff for: en/integer_array/kth_largest_element.md

+57-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ Trail and error: Comparison-based sorting algorithms don't work because they inc
2929

3030
By quick sorting, we get the final index of a pivot. And by comparing that index with `K`, we decide which side (the greater or the smaller) of the pivot to recurse on.
3131

32-
### Java
32+
### Java - Recursion
3333

3434
```java
3535
public class Solution {
@@ -79,6 +79,62 @@ b. final index of pivot equals K.
7979

8080
Since 'Kth **largest**' is wanted, numbers greater than pivot are placed to the left and numbers smaller to the right, which is a little different with typical quick sort code.
8181

82+
### Java - Iteration
83+
84+
Recursive code is easier to read than to write, and it demands some experience and skill. Here is an iterative implementation.
85+
86+
```
87+
class Solution {
88+
public int findKthLargest(int[] A, int k) {
89+
if (A == null || A.length == 0 || k < 0 || k > A.length) {
90+
return -1;
91+
}
92+
93+
int lo = 0, hi = A.length - 1;
94+
while (lo <= hi) {
95+
int idx = partition(A, lo, hi);
96+
if (idx == k - 1) {
97+
return A[idx];
98+
} else if (idx < k - 1) {
99+
lo = idx + 1;
100+
} else {
101+
hi = idx - 1;
102+
}
103+
}
104+
105+
return -1;
106+
}
107+
108+
private int partition(int[] A, int lo, int hi) {
109+
int pivot = A[lo], i = lo + 1, j = hi;
110+
while (i <= j) {
111+
while (i <= j && A[i] > pivot) {
112+
i++;
113+
}
114+
while (i <= j && A[j] <= pivot) {
115+
j--;
116+
}
117+
if (i < j) {
118+
swap(A, i, j);
119+
}
120+
}
121+
swap(A, lo, j);
122+
123+
return j;
124+
}
125+
126+
private void swap(int[] A, int i, int j) {
127+
int tmp = A[i];
128+
A[i] = A[j];
129+
A[j] = tmp;
130+
}
131+
}
132+
```
133+
134+
### Src Code Analysis
135+
136+
The `while` loop in `findKthLargest` is very much like that in `binary search`. And `partition` method is just the same as quick sort partition.
137+
82138
### Complexity
83139

84140
Time Complexity. Worse case (when the array is sorted): ***n + n - 1 + ... + 1 = O(n^2)*** . Amortized complexity: ***n + n/2 + n/4 + ... + 1 = O(2n)=O(n)*** .

Diff for: zh-hans/integer_array/kth_largest_element.md

+57-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ adding this problem and creating all test cases.
2727

2828
找第 K 大数,基于比较的排序的方法时间复杂度为 $$O(n)$$, 数组元素无区间限定,故无法使用线性排序。由于只是需要找第 K 大数,这种类型的题通常需要使用快排的思想解决。[Quick Sort](http://algorithm.yuanbin.me/zh-hans/basics_sorting/quick_sort.html) 总结了一些经典模板。这里比较基准值最后的位置的索引值和 K 的大小关系即可递归求解。
2929

30-
### Java
30+
### Java - 递归求解
3131

3232
```java
3333
public class Solution {
@@ -76,6 +76,62 @@ public class Solution {
7676
递归的终止条件有两个,一个是左边界的值等于右边界(实际中其实不会有 l > u), 另一个则是索引值 `m + 1 == k`.
7777
这里找的是第 K 大数,故为降序排列,for 循环中使用`nums[i] > nums[left]` 而不是小于号。
7878

79+
### Java - 迭代求解
80+
81+
递归代码看上去顺理成章,实际上构造递归方法的参数、返回值是需要经验技巧的,自己写起来就会发现机关重重,一次性做到 bug-free 并不容易。下面是一个迭代版的实现。
82+
83+
```
84+
class Solution {
85+
public int findKthLargest(int[] A, int k) {
86+
if (A == null || A.length == 0 || k < 0 || k > A.length) {
87+
return -1;
88+
}
89+
90+
int lo = 0, hi = A.length - 1;
91+
while (lo <= hi) {
92+
int idx = partition(A, lo, hi);
93+
if (idx == k - 1) {
94+
return A[idx];
95+
} else if (idx < k - 1) {
96+
lo = idx + 1;
97+
} else {
98+
hi = idx - 1;
99+
}
100+
}
101+
102+
return -1;
103+
}
104+
105+
private int partition(int[] A, int lo, int hi) {
106+
int pivot = A[lo], i = lo + 1, j = hi;
107+
while (i <= j) {
108+
while (i <= j && A[i] > pivot) {
109+
i++;
110+
}
111+
while (i <= j && A[j] <= pivot) {
112+
j--;
113+
}
114+
if (i < j) {
115+
swap(A, i, j);
116+
}
117+
}
118+
swap(A, lo, j);
119+
120+
return j;
121+
}
122+
123+
private void swap(int[] A, int i, int j) {
124+
int tmp = A[i];
125+
A[i] = A[j];
126+
A[j] = tmp;
127+
}
128+
}
129+
```
130+
131+
### 源码分析
132+
133+
`findKthLargest` 里的 `while` 循环体有种二分搜索的既视感,`partition` 就是标典型的快排分区写法。
134+
79135
### 复杂度分析
80136

81137
最坏情况下需要遍历 $$ n + n - 1 + ... + 1 = O(n^2)$$, 平均情况下 $$n + n/2 + n/4 + ... + 1 = O(2n)=O(n)$$. 故平均情况时间复杂度为 $$O(n)$$. 交换数组的值时使用了额外空间,空间复杂度 $$O(1)$$.

0 commit comments

Comments
 (0)